Git

Git

fetch150zy

git以及github的一些基本操作

Git 常用操作

一、本地仓库

1. init

  • 初始化本地仓库(主要用于客户端)

    1
    git init
  • 创建裸库

    用于作为大家一起工作的共享库,每一个人都可以往里面push自己的本地修改

    1
    2
    3
    mkdir <example.git>
    cd <example.git>
    git init --bare .

    在工作目录只有一个.git目录,没有类似本地库那样的文件结构可供你直接进行浏览和修改

    但你可以使用git show来进行浏览,参数为某次commit的SHA1值

    1
    git show <id>
  • 本地仓库与裸库连接

    1
    git remote add <remote> <path>/<example.git>

2. config

  • 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    git config --global user.name "username"
    git config --global user.email "email" # 初始化用户和邮箱
    git config --list # 检查当前配置
    git config --local --list # (当前目录)
    git config --global --list # (全局)
    git config <key> # 检查git的某一项配置
    git config --global core.editor vim # 设置默认文本编辑器
    git config --global merge.tool vimdiff # 差异分析工具
    git config --global alias.br <branch> # 设置命令别名
    git config --global --unset <entry-name> # 删除全局设置
    git config core.fileMode false # 忽略文件的权限变化
    git config credential.helper store # 保存凭证(避免每次pull或push的时候询问帐号密码)
  • git配置http和scoks代理

    1
    2
    3
    git config --global https.proxy 'http://127.0.0.1:8001' # 适用于privoxy将socks协议转为http协议的http端口
    git config --global http.proxy 'http://127.0.0.1:8001'
    git config --global socks.proxy "127.0.0.1:1080"
  • git配置ssh代理

    1
    2
    3
    4
    5
    6
    cat ~/.ssh/config
    # Host gitlab.com
    ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p # 直接使用 shadowsocks 提供的
    socks5 代理端口
    # Host github.com
    ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p

3. clone

  • 克隆仓库

    1
    2
    3
    4
    git clone https://github.com/Marszhewei/Cmake.git
    git clone https://github.com/Marszhewei/Cmake.git cmake # 指定本地仓库名
    git clone -b <branch-name> --single-branch https://github.com/user/repo.git # clone下来指定的单一分支
    git clone --depth=1 https://github.com/user/repo.git # clone最新一次提交

4. add

  • 添加

    1
    2
    3
    git add <file>
    git add *.md # 正则匹配
    git add <dir>/
    1
    2
    3
    git add .
    git add -A # 添加全部文件
    git add * # 不包含隐藏文件
  • 交互式暂存

    1
    git add -i

5. commit

1
git update-ref -d HEAD		# 清空commit重新提交第一个commit
  • 提交更新到本地库

    1
    2
    3
    4
    git commit
    git commit -v # 查看当前stage区与上一个版本的差异(填写comments后直接提交到本地库了)
    git commit [[--message | -m] <"comments">] # 添加简短提交信息
    git commit -a -m <"comments"> # 跳过暂存区,直接提交到本地库(untracked文件不能用)
  • 将暂存区的文件重新提交,将目前的修改追加到上一次提交中

    1
    git commit --amend		# 修改最后一次提交

    类似于变基,如果最后一次提交已经push了就不要使用了

  • 优雅的提交commit信息

    1. 组成部分
      • 标题行: 必填, 描述主要修改类型和内容
      • 主题内容: 描述为什么修改, 做了什么样的修改, 以及开发的思路等等
      • 页脚注释: 放 Breaking Changes 或 Closed Issues
    2. 常用修改项
      • type: commit 的类型
      • feat: 新特性
      • fix: 修改问题
      • refactor: 代码重构
      • docs: 文档修改
      • style: 代码格式修改, 注意不是 css 修改
      • test: 测试用例修改
      • chore: 其他修改, 比如构建流程, 依赖管理.
      • scope: commit 影响的范围, 比如: route, component, utils, build…
      • subject: commit 的概述
      • body: commit 具体修改内容, 可以分为多行
      • footer: 一些备注, 通常是 BREAKING CHANGE 或修复的 bug 的链接.

6. status

  • 检查当前文件状态

    1
    2
    git status
    git status --ignored # 展示忽略的文件
  • 获得简短的状态输出

    1
    git status [-s | --short]

7. reset

  • reset中三棵树

    1
    2
    3
    4
    5
    6
    git reset --soft
    # 仅移动HEAD指针,只回退了commit
    git reset --mixed
    # 重置HEAD,重置暂存区,工作区不会被修改,这时git add 和 git commit 即可回到之前状态
    git reset --hard
    # 彻底回退到指定commit-id的状态
  • revert & reset

    1
    2
    3
    git revert <id>	# 以新增一个commit的方式还原某一个commit的修改
    reset 命令会抹去某个 commit id 之后的所有 commit
    git revert -m 1 HEAD # 撤销一步(工作区暂存区本地仓库均撤销)
Level HEAD Index Workdir safe
Commit Level
reset –soft [commit-id] 移动了HEAD指向的分支引用 NO NO YES
reset –mixed [commit-id] 移动了HEAD指向的分支引用 YES NO YES
reset –hard [commit-id] 移动了HEAD指向的分支引用 YES YES NO
checkout [commit-id] 只移动了HEAD YES YES YES
File Level
reset (commit-id) [file] NO YES NO YES
checkout (commit-id) [file] NO YES YES NO

8. stash

  • 查看存储栈

    1
    git stash list
  • 保存到存储栈

    1
    2
    3
    git stash [save <"comments">]		# 将现在工作区和暂存区的更改保存到存储栈(已跟踪)
    git stash [save <"comments">] -u # 存储未跟踪的文件
    git stash --keep-index # 存储工作区的更改而忽视暂存区的修改
  • 从存储栈恢复

    1
    2
    3
    4
    git stash pop	# 从栈顶恢复并出栈
    git stash pop stash@{2} # 从栈的任意位置恢复内容并出栈
    git stash apply # 从栈顶恢复但不删除
    git stash apply stash@{2} # 从栈的任意位置恢复但不删除
  • 从存储栈删除

    1
    2
    3
    git stash drop	# 从栈顶移除记录
    git stash drop stash@{2} # 从任意位置移除记录
    git stash clear # 清空存储栈

    drop后可跟stash_id,不加参数就是删除最近一条

9. clean

1
2
3
4
5
git clean -d -n			# 做一次演习然后告诉你将要移除什么
git clean -d -f # 强制移除工作目录中所有未追踪的文件以及空的子目录
git clean -i -d # 交互式
git clean -x -d # 删除构建时的.o文件
git clean -X -f # 清除.gitignore文件中记录的文件
  • 强制删除untracked的文件&目录

    1
    2
    git clean <file-name> -f
    git clean <directory-name> -df

10. show

1
2
git show <branch-name>:<file-name>	# 展示任意分支的某一文件的内容
git blame <file-name> # 查看这段代码是谁写的
1
2
3
git show <tagname>	# 查看标签信息与对应的提交信息
git show <id> # 显示某次提交的更改
git show <id> -name-only # 显示这次提交修改了什么文件

11. branch

  • 创建分支

    1
    2
    3
    git branch test			# 创建分支
    git branch <branch> <id> # 从任意提交创建分支
    git branch <branch> <old-branch> # 从现有分支创建分支
  • 查看分支

    1
    2
    3
    4
    5
    6
    7
    git branch	# 列出全部分支
    git branch -v # 列出全部分支并查看每个分支的最后一次提交
    git branch -vv # 将所有的本地分支列出来并且包含更多的信息
    git branch --merge # 查看哪些分支已经合并到当前分支
    git branch --no-merged # 查看所有包含未合并工作的分支
    git branch -a # 查看全部本地分支和远程分支
    git branch -r # 查看全部的远程分支
  • 切换跟踪的远程分支

    1
    git branch -u origin/serverfix	# 设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支
  • 删除分支

    1
    2
    git branch -d test	# 删除分支
    git branch -D test # 强制删除分支

    在该分支代码未合并到master分支时,直接删除会不成功

  • 重命名本地分支

    1
    git branch -m <branch>

12. checkout

1
2
3
4
5
6
7
git checkout <branch>		# 切换分支
git checkout -b <branch> # 创建并切换到分支
git checkout -b <branch> <id> # 在特定的commit上创建一个新分支
git checkout - # 快速切换到上一个分支
git checkout <id> # 切换到某次提交
git checkout <tag> # 切换tag
git checkout -b <branch> <tag> # 在特定的标签上创建一个新分支
  • 撤销对文件的修改

    1
    2
    git checkout <file>
    git checkout . # 放弃工作区所有修改

    撤销还没有进暂存区的文件

  • 跟踪远程分支,并在本地创建同名分支(迁移本地)

    1
    2
    git checkout --track origin/dev
    git checkout -b serverfix origin/serverfix # 相同,但是后一种本地分支和远程分支可以使用不同名

13. merge

  • 合并分支

    1
    2
    git merge <branch>
    git merge <branch> -no-ff -m <commit message> # 合并指定分支到当前分支(-no-ff 参数表示禁用Fast forward)

    merge比较暴力,直接腾出区域把另一个分支全放进去,好处是可以知道哪些代码是来

    自哪一个分支的rebase会按照一定顺序进行重新排序,然后再放入,但是不知道哪些代

    码来自哪个分支修改文件出现冲突时需要操作者手动修改再进行合并

  • 操作项

    1
    2
    git merge --abort		# 在遇到冲突时终止合并
    git merge --continue # 冲突解决后继续merge
  • 关于空白问题导致的冲突

    1
    2
    git merge -Xignore-space-change whitespace	# 忽略所有空白修改
    git merge -Xignore-all-space whitespace # 忽略任意数量已有空白修改

13. tag

  • 列出标签

    1
    2
    git tag					# 列出现有标签
    git tag -l <tagname> # 查找标签(特定模式)
  • 贴上标签

    1
    2
    3
    4
    git tag <tagname>						# 创建轻量标签
    git tag <tagname> <id> # 给某次提交创建一个轻量标签
    git tag -a <tagname> -m <"tag comments"> # 创建附注标签
    git tag -a <tagname> <id> -m <"tag comments"> # 给某次提交创建一个附注标签
  • 删除标签

    1
    git tag -d v1.4

15. diff

  • 详细展示一行中的修改

    1
    git diff --word-diff
  • 工作目录中当前文件和暂存区域快照之间的差异

    1
    git diff <file>
  • 比较暂存区和版本库的差异

    1
    git diff --staged/--cached
  • 指定范围内比较

    • 对比两次提交

      1
      2
      3
      git diff <id1> <id2>
      git diff <id>^ # 和上一次提交进行比较
      git diff <id1> <id2> <path>/<file> # 限制比较的范围
    • 对比两个分支

      1
      git diff <branch-a> <branch-b>

16. log

1
git reflog	# 引用日志
  • 显示最近的两条提交记录

    1
    2
    git log -n		# -n用来显示最近的n次提交
    git log -p # -p用来显示每次提交的内容差异
  • 使用其它格式显示历史提交信息

    • 查看提交历史

      1
      2
      3
      4
      5
      git log
      git log --pretty=oneline # 一行输出一条提交记录
      git log --pretty=short # 简短显示log
      git log --pretty=full # 完整显示log
      git log --pretty=fuller # 更加完整的显示log
    • 更改显示的格式

      1
      git log --pretty=format:"%h - %an, %ar : %s"
      1
      2
      3
      4
      %H 提交的完整哈希值 %h 提交的简写哈希值 %T 树的完整哈希值 %t 树的简写哈希值
      %P 父提交的完整哈希值 %p 父提交的简写哈希值 %an 作者名字 %ae 作者的电子邮件地址
      %ad 作者修订日期(可以用 --date=选项 来定制格式) %ar 作者修订日期,按多久以前的方式显示
      %cn 提交者的名字 %ce 提交者的电子邮件地址 %cd 提交日期 %cr 提交日期(距今多长时间) %s 提交说明
  • 图形化显示合并提交分支历史

    1
    2
    3
    git log --stat			# 查看简要提交变更
    git log --shortstat # 只显示 --stat 中最后的行数修改添加移除统计
    git log --graph # 图形化展示提交历史
  • 日志搜索

    1
    2
    3
    4
    git log --after/--since=2.week			# 两周之内的提交
    git log --after/--since="2022-8-8" # 此日期之后的提交
    git log --before/until="2022-8-3" # 此日期之前的提交
    git log --before/--until=2.week # 两周之前的提交
    1
    2
    3
    git log --author <author>		# 仅显示包含作者的提交
    git log --committer <commiter> # 仅显示指定提交者相关的提交
    git log -- <path>/<file> # 仅显示文件相关的提交
    1
    2
    3
    4
    git log master dev			# 查看dev和master分支的所有commit
    git log master..dev
    git log ^master dev
    git log dev --not master # dev分支还未合并到master分支上的提交
    1
    2
    git log <branch-a> <branch-b> ^<branch-c>
    git log <branch-a> <branch-b> --not <branch-c> # branch-a,branch-b包含,branch-c不包含的提交
    1
    git log master...dev		# 查看两次提交的非共有提交
    1
    2
    3
    git log -S <string>					# 只显示添加或删除该字符串的那些提交
    git log -G <string> # 使用正则表达式进行搜索
    git log -L :<function>:<file> # 将文件中的函数改动全部列出来
    1
    git log --grep <keywords>				# 仅显示包含关键字的搜索
  • others

    1
    2
    3
    4
    git log --name-only			# 显示提交修改了什么文件
    git log --abbrev-commit # 仅显示SHA-1前几个字符
    git log --show-signature # 显示GPG签名
    git log --name-status # 显示新增、修改、删除的文件清单

17. rebase

1
git rebase --autostash	# 执行rebase之前自动stash

谨慎使用: 不要将已经推送到中央服务器中的提交包含在内,这样做会出现相同变更的不同版本,造成混乱

  • 对分支变基消除钻石链

    1
    2
    3
    4
    git checkout <topic-branch>
    git rebase <base-branch>
    git checkout <base-branch>
    git merge <topic-branch>
    1
    2
    3
    git rebase <base-branch> <topic-branch>
    git checkout <base-branch>
    git merge <topic-branch>
  • 当使用rebase导致混乱

    1
    2
    3
    4
    git pull --rebase
    # or
    git fetch
    git rebase <remote>/<branch>
  • 改变历史

    1
    git rebase -i HEAD~3

    pick reword edit squash fixup exec

18. grep

  • 从提交历史或者工作目录中查找

    1
    2
    3
    4
    git grep -n <string>		# -n参数输出匹配行行号
    git grep --count <string> # --count输出哪些文件包含了该string及次数
    git grep -p <string> <file> # 查看该string属于哪个函数
    git grep --break --heading # 易于阅读

19. filter-branch

  • 从每一个提交中移除一个文件

    1
    git filter-branch --tree-filter "rm -f <file>" HEAD
  • 将一个子目录作为新的根目录

    1
    git filter-branch --subdirectory-filter <dir> HEAD
  • 全局修改邮箱地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    git filter-branch --commit-filter '
    if [ "$GIT_AUTHOR_EMAIL" = <"old-email"> ];
    then
    GIT_AUTHOR_NAME=<"author">;
    GIT_AUTHOR_EMAIL=<"new-email">;
    git commit-tree "$@";
    else
    git commit-tree "$@";
    fi' HEAD

19. rm mv

  • 移除文件

    1
    2
    3
    rm <file>
    git rm <file> # 该文件在工作区
    git rm -f <file> # 该文件在暂存区
    1
    git rm --cached <file>	# 把文件从git仓库中删除,但是本地保留
  • 移动文件

    1
    2
    3
    4
    git mv <file-from> <file-to>	# 相当于运行下面三条命令
    mv <file-from> <file-to>
    git rm <file-from>
    git add <file-to>

20. 其它

  • ls-file

    1
    2
    3
    git ls-files -t			# 显示所有tracked的文件
    git ls-files --others # 显示所有untracked的文件
    git ls-files --others -i --exclude-standard # 显示所有忽略的文件
  • 忽略文件的改动

    1
    2
    3
    git update-index --assume-unchanged path/to/file	
    # 关闭 track 指定文件的改动,也就是 Git 将不会在记录这个文件的改动
    git update-index --no-assume-unchanged path/to/file # 恢复 track 指定文件的改动
  • 以最后提交的顺序列出所有git分支

    1
    git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads/

二、远端仓库

1. remote

  • 列出远端仓库

    1
    2
    3
    git remote
    git remote -v # 显示读写远程仓库使用的Git保存的简写与其对应的URL
    git remote show <remote> # 查看远程仓库和本地仓库的对应关系
  • 添加更改远程仓库

    1
    git remote add <remote> <url>/<local.git>	# 添加远程仓库
    1
    2
    git remote rename <old-remote> <new-remote>	# 重命名远程仓库
    git remote set-url <remote> <url> # 修改远程仓库的url
  • 移除远程仓库

    1
    2
    git remote rm origin	# 移除远程仓库
    git remote prune origin # 远程删除了分支本地也删除

2. push

  • 推送到远端仓库

    1
    2
    git push <remote> <branch>		# 同名
    git push <remote> <local_branch>:<remote_branch> # 不同名
  • 推送标签到远端仓库

    1
    2
    git push <remote> <tag>		# 推送一个标签
    git push <remote> --tags # 推送多个标签
  • 移除/删除远端分支

    1
    2
    git push <remote> :<branch>
    git push <remote> --delete <branch>

3. pull

  • 拉取分支最新内容 pull = fetch + merge

    1
    git pull <remote> <branch>   
  • 变基

    1
    git pull --rebase

4. fetch

  • 从远端仓库拉取并不会自动合并

    1
    2
    git fetch <remote> <branch>
    git fetch <remote> pull/<id>/head:<branch> # 从远程仓库根据id拉下某一状态到本地分支
  • 抛弃本地所有修改回到远程仓库的状态

    1
    git fetch --all && git reset --hard <remote>/<branch>

三、服务器上的Git

1. 四种协议

  • 本地协议

    1
    2
    git clone <path>/<local.git>				# 硬链接或直接复制
    git clone file://<path>/<local.git> # 没有外部参考的干净版本库副本
    1
    git remote add <remote> <path>/<example.git>
  • HTTP协议

  • SSH协议

  • Git协议

2. 在服务器上搭建Git

  • 创建裸库

    1
    2
    3
    git init --bare
    # or
    git clone --bare <repo> <repo.git>
  • 将裸库上传服务器

    1
    2
    3
    4
    5
    6
    scp -r <repo.git> user@git.example.com:/opt/git
    git clone user@git.example.com:/opt/git/<repo.git> # 注意权限(要有可读权限)

    ssh user@git.example.com
    cd /opt/git/<repo.git>
    git init --bare --shared # Git会自动更改权限为可写(--shared)

3. 签署工作

  • GPG

    1
    2
    3
    gpg --list-keys		# 配置 GPG 并安装个人密钥
    gpg --gen-key # 还未安装密钥,生成一个
    git config --global user.signingkey <key> # 签署
  • 签署标签

    1
    2
    git tag -s <tag> -m <"tag comments">		# -s替换-a
    git show <tag> # 你会看到GPG签名
    1
    git tag -v <tag>	# 验证标签(签署者的公钥需要在你的钥匙链中)
  • 签署提交

    1
    git commit -a -s -m <"comments">	
    1
    git log --show-signature	# 查看签名

四、Git在生产中的应用

1. master分支

线上分支,主分支,中小规模项目作为线上运行的应用对应的分支。

2. develop分支

是从master创建的分支,一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线要求,都可以在此版本进行开发,阶段开发完成后,需要合并到master主分支上,准备上线。

3. feature/xxxx分支

从develop创建的分支,是开发新功能的分支,一般是同期并行发布,但不同期上线时创建的分支,分支上的研发任务完成后merge到develop分支。

4. hotfix/xxxx分支

从master派生的分支,一般作为线上(master)bug修复使用,修复完成后要合并到master,test,develop分支。

5. release

准备要发布版本的分支,用来修复bug,基于develop,完成后merge回develop和master

6. 其他

test分支(用于代码测试),pre分支(用于预上线)

Github

一、SSH TOKEN

1. SSH

1
2
ssh-keygen -t rsa	# 生成SSH公钥
cat ~/.ssh/id_rsa.pub # 获取公钥
  • 验证是否配置成功

    1
    2
    ssh -T git@gitee.com
    ssh -T git@github.com
  • 配置git服务器

    1
    2
    3
    4
    5
    $ sudo adduser git
    $ su git
    $ cd
    $ mkdir .ssh && chmod 700 .ssh
    $ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

    我们将使用 authorized_keys 方法来对用户进行认证。同时我们假设你使用的操作系统是标准的 Linux 发行版

    首先,创建一个操作系统用户 git,并为其建立一个 .ssh 目录

    1
    2
    3
    $ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
    $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
    $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys

    将这些公钥加入系统用户 git 的 .ssh 目录下 authorized_keys 文件的末尾

    1
    2
    3
    4
    5
    $ cd /opt/git
    $ mkdir project.git
    $ cd project.git
    $ git init --bare
    Initialized empty Git repository in /opt/git/project.git/

    现在我们来为开发者新建一个空仓库

2. token

1
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

二、github常用功能

1. Watch Star Fork

​ Watch: 观察(关注)

​ Star: 点赞(对项目的支持)

​ Fork: 获得别人项目的一份拷贝(在获得仓库管理者的merge后你的项目

2. Code

​ 你项目的代码文件(建议加一个readme,方便别人使用)

3. Issues

​ 该项目的一些问题或者bug

​ 分为解决的问题(close)和待解决(open)

4. Pull requests

​ 一般先将别人的项目fork到你自己的仓库(相当于是原项目的分支)

​ 然后你把项目再clone到本地

​ 修改完成后push到远端仓库

​ 通过pull requests提交PR

​ 等待原作者review你的代码,如果接受,你就是项目的贡献者之一了

5. Projects

​ 分类Issues, pull requests等

6. Wiki

​ 说明文档

7. Pulse

​ 汇总概况

8. Graphs

​ 以图的形式展开项目整体情况

三、Git Flow

1. gitflow工具

  • git flow feature start A 创建以feature开头的分支

  • git flow feature finish A 合并到develop分支

    如果是hotfix或者release分支甚至会自动帮你合并到develop、master