学习笔记- Git 相关的命令。

Git 是分布式版本管理系统,SCN 是集中式(服务器挂了就没有了),Git 跟踪并管理的是修改,而非文件。

  • Workspace 工作区是我们平时编辑文件的地方
  • Index / Stage 暂存区, 使用 git add将编辑好的命令放到一个临时地方,叫做Index,如果加入了不希望加入的文件,那么使用 git rm --cache 移除
  • local repo 本地仓库
  • remote repo 远程仓库

一、新建代码块

1
2
3
git init # 在当前目录下新建代码库
git init project_name # 新建一个目录 初始化为git 代码库
git clone url # 下载一个项目和整个代码的历史

二、 配置

1
2
3
4
5
git config --list # 显示当前 git 配置
git config -e [--global] # 编辑git 配置文件,如果没有 `--global` 那么是当前仓库的配置;否则是整个用户的

git config [--global] user.name "name" 
git config [--global] user.email "email_address"

三、增加/ 删除文件

1
2
3
4
5
git add [file1] [file2] [dir] # 将指定的文件放到暂存区,文件夹包括子目录
git add . # 将当前目录的所有文件放到暂存区

git rm --cached [file] # 文件保留在工作局,但是从暂存区删除了

四、代码提交

1
2
git commit -m [message] # 从暂存区 提交到仓库, 并加上message
git commit [file1] [file2] -m [message] # 指定文件从暂存到 仓库

五、分支

  • 每一次git commit,都会生成一个commit id记录该次提交,Git都会将它们串成一条时间线,这条时间线就是一个分支。
  • 因为创建、合并、删除分支都很快,所以git鼓励你使用分支完成某个任务,合并后再删除分支。过程比直接在master分支工作更安全,且效果一样。
  • 分支策略:master分支应该是非常稳定的,仅用来发布新版本,平时不能在上面干活,干活都在dev分支,dev是不稳定的,到1.0发布时,再将dev合并到master上,由master发布新版本。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
git branch # 列出所有本地分支
git branch -r  # 列出所有远程分支
git branch -a # 列出所有本地分支和远程分支

git branch [branch_name] # 新建分支,但是依然留在当前分支
git checkout [branch_name] # 切换到指定分支

git checkout -b [branch_name] #新建分支,并切换到 branch_name 分支 
git checkout -  # 切换到上一个分支

git merge [branch_name] #合并指定分支到当前分支

git branch -d [branch_name] # 删除本地分支
git branch -D [branch_name] #  -d 只能删除已经参与合并的分支,但对于未参与合并的分支是无法删除的,如果想要强制删除,那么使用-D

#删除远程分支
git push origin --delete [branch_name] 
git branch -dr [remote/branch] 

[remote rejected] master -> master (pre-receive hook declined) 解决方案

方法一: 将所在的项目分支 的protected 权限关闭

方法二: 新建其它分支,将项目push 上去,后期再进行merge

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# (1) 新建分支
git branch 分支名

# (2) 切换分支
git checkout 分支名

# (3) 上传项目
git add .
git commit -m "message"
git remote add origin 仓库地址
git push -u origin 分支名

六、标签版本(tag)操作

1
2
3
4
5
git tag # 查看版本
git tag [name] # 创建版本
git tag -d [name] # 删除版本
git tag -r # 查看远程版本

为什么有了 commit id 还需要tag呢? 因为tag 是有意义的名字,比较好找,可以和commit 绑定在一起。

六、查看信息

1
2
3
4
5
6
7
git status # 显示所有有变更的文件
git log # 显示当前分支的版本历史

git diff # 显示暂存区和工作区的差异
git diff README.md # 查看具体修改了什么内容
git diff --cached [file] # 显示暂存和上一个 commit 的差异

七、远程同步

1
2
3
4
5
git remote show []

git push [remote] [branch] # 上传本地指定的分支到远程仓库
git push [remote]  --force # 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --all # 推送所有分支到远程仓库

git clone vs git pull

git clone is how you get a local copy of an existing repository to work on. It’s usually only used once for a given repository, unless you want to have multiple working copies of it around. (Or want to get a clean copy after messing up your local one…)

git pull (or git fetch + git merge) is how you update that local copy with new commits from the remote repository. If you are collaborating with others, it is a command that you will run frequently.

git pull 在团队协作的时候用得很多,相当于是增量的修改本机的 repository;git clone 是将 repository 完全拷贝到本地。

1
2
git clone repo_url --depth 1
# depth用于指定克隆深度,为1即表示只克隆最近一次commit.

一般仓库文件不大时,我们都可以用这个方法git clone仓库,但问题是有时候,在仓库历史的某次commit时,有人不小心提交了1G的文件,虽然后面的commit中他把这个文件删除了,但是在.git文件夹中仍然存储着这个文件,所以如果我们克隆仓库这个仓库,会把所有的历史协作记录都clone下来,这样整个文件会非常大,其实对于我们直接使用仓库,而不是参与仓库工作的人来说,只要把最近的一次commit给clone下来就好了。这就好比一个产品有很多个版本,我们只要clone最近的一个版本来使用就行了。实现这个功能就需要用到git clone –depth=1命令

add all files to a commit except a single file

方法一:先加入到 暂存区,然后从暂存区删除(工作区是没有删除的)

1
2
git add -u
git reset -- main/dontcheckmein.txt

方法二:使用正则匹配,加入相应的文件到暂存区。

需要对正则比较熟悉,并且文件名有规则。

放弃本地修改,强制覆盖本地代码

1
2
3
git fetch --all # 从远程到local repo(和 git push 是逆操作)
git reset --hard origin/master # reset 表示回退到某一版本
git pull # 这个有点重复

八、撤销

1
2
git checkout [file] # 恢复暂存区的指定文件到工作区
git checkout . # 恢复暂存区的所有文件到工作区

通常git将(每个branch中的)文件分成了4个区域。

  1. 我们平时编辑的文件在workspace区。
  2. 当文件编辑完成,我们需要将文件备份到git的时候,我们把这些文件选择出来,放到一个临时的区域,叫index.
  • 添加这个过程是通过git add 命令来实现的。
  • 如果不小心添加了不想要的文件,通过git rm –cache命令来移除
  1. 当想提交的文件都放入到index临时区之后,可以进行正式的提交
  • 正式提交需要用git commit这个命令。
  • 在使用git commit的时候,需要写一段提交程序的更改说明。通常说明的第一行是一个很简短的介绍。然后是内容的正文。在正文中,可以利用github提供的一些关键字,将commit同github上面的issue和pull request联系起来。比如我们可以写 “fix #32”,那么当这个commit被提交到github上去之后,第32号bug也就会自动关闭。这样后面的人看到这个commit的时候,也比较方便找到它对应的bug是什么。
  1. 一旦commit成功,本次更改就写进了git的历史了。但是这时候还没有和github同步(remote branch)。同步是通过git push 命令完成的。一般是git push 远程的git repo名称 本地要提交的branch名。比如git push origin shiy_dev 就是说把我本地的shiy_dev 这个branch里的commit都推送到远端的叫做origin的这个repo
  • 我们可以有很多个远端的repo。比如可以同时拥有gitlab和github的远端repo。需要查看目前有哪些远端的repo,我们可以用git remote -v命令。
  • 需要添加新的远端repo,可以用git remote add 命令。
  1. 很多时候git push命令会失败。原因是有其他的人对同样的branch进行了改动。这时候我们需要先把对方提交的文件取到本机,看看是不是有矛盾的地方。这是通过git pull 远端git repo名称 远端的branch名 来实现的。 远端的文件取到之后,git会尝试自动和本地的文件进行整合。整合成功的话,叫fastforward merge。通常当大家改动了不同的文件的时候,merge都会比较容易。如果大家改动的文件有冲突,就会有merge conflict。这时候git会报告有conflict的文件,需要我们打开查看,并且纠正。当纠正完成之后,需要重新用git add 命令将纠正过的文件添加到index然后再次git commit,和git push。
  2. 当很多人同时在改一个git repo的相同branch下的文件的时候,会频繁出现merge conflict。再有就是代码需要经过充分的测试才好提交到正式的branch (master),这样不会影响到其他的开发者。所以建议大家在文件进行改动的时候全部都在单独的branch中进行。
  • 建立一个新的branch,使用git checkout -b branch名称 这个命令。
  • 通常会有很多branch。如果需要切换,可以用git checkout branch名称
  • 如果一个branch已经提交,不再需要了,可以用git branch -d branch名称 来操作
  1. 如何查看文件更改历史
  • 可以用git log来查看commit的历史
  • 用git blame 来查看每一行文件的改动记录
  • 在Linux下,我用gitk这个图形工具来查看
  1. 当文件被push到远端(github)的branch的时候,还需要经过code review,然后才正式可以master branch合并。这时候需要提交一个pull request. 这一步可以直接通过网站上点选完成。

九、多项目管理

Google Git-Repo 多仓库项目管理

Git多分支平行发展(一个仓库包含多个不同的项目)

在github同一个仓库立上传多个项目 如何在github同一个仓库上传多个项目

Git多项目管理

使用git下载repo中的子文件夹而非整个文件夹

How do I clone a subdirectory only of a Git repository?

下载某个分支(非master)

下载某个分支的代码(默认是 master)

git clone -b cla https://github.com/jina-ai/jina.git # 分支的名字叫做 cla

Git 使用

add all files to a commit except a single file

方法一:先加入到 暂存区,然后从暂存区删除(工作区是没有删除的)

1
2
git add -u
git reset -- main/dontcheckmein.txt

方法二:使用正则匹配,加入相应的文件到暂存区。

需要对正则比较熟悉,并且文件名有规则。

参考文献

更多命令的详解,参考以下链接:

Git Book

gitlab 用户组中的五种权限

Gitlab用户在组中有五种权限:Guest、Reporter、Developer、Master、Owner

Guest:可以创建issue、发表评论,不能读写版本库 Reporter:可以克隆代码,不能提交,QA、PM可以赋予这个权限 Developer:可以克隆代码、开发、提交、push,RD可以赋予这个权限 Master:可以创建项目、添加tag、保护分支、添加项目成员、编辑项目,核心RD负责人可以赋予这个权限 Owner:可以设置项目访问权限 - Visibility Level、删除项目、迁移项目、管理组成员,开发组leader可以赋予这个权限 Gitlab中的组和项目有三种访问权限:Private、Internal、Public

Private:只有组成员才能看到 Internal:只要登录的用户就能看到 Public:所有人都能看到 开源项目和组设置的是Internal

更多的信息:Gitlab成员权限分配规则

十、Git 自动检查

(在团队写作中,十分有必要借助一些工具来约束我们的代码格式)

如果基于的开源项目比较小(文件比较少),那么建议自己集成一下,这样不用安装也可以使用。

脚本目前实现的两个功能:

  • 检查commit 信息
  • format code

使用步骤:

  • Template-python 中的三个文件(.githooks, .flake8.gitignore)放到项目的根目录中

  • git init

  • 将 git 升级到最新版本,然后执行 git config core.hooksPath .githooks

  • 安装相应的依赖 pip install black isort flake8

1
git commit -m "Some comments" --no-verify

提交不进行检查的操作

black 是python 代码格式化工具

为了帮助开发者统一代码风格,Python 社区提出了 PEP8 代码编码风格,它并没有强制要求大家必须遵循,Python 官方同时推出了一个检查代码风格是否符合 PEP8 的工具,名字也叫 pep8,后来被重命名为了 pycodestyle。

Black,号称不妥协的代码格式化工具,为什么叫不妥协呢?因为它检测到不符合规范的代码风格直接就帮你全部格式化好,根本不需要你确定,直接替你做好决定。Black 并不是完全按照 PEP8 规范进行格式化的, Black 是 PEP8 的严格子集。

可以集成到 Pycharm 中进行使用,也可以在 git commit 之前进行使用。

使用也非常简单:只需要在 black 命令后面指定需要格式化的文件或者目录就行了。

1
black code.py

isort 会对 import 语句记性排序和分段。其将语句分为标准库、第三方库和本地库三种 ,分被你按照字母排序。格式化的结果,能自动满足 Pylint 的需要,实际上,它本身就是 Pylint 的一个依赖。

使用

1
2
3
4
5
6
import isort
code = """
import tkinter as tk
import pygame, sys
"""
print(isort.code(code))

flake8 是 python 官方发布的辅助监测 Python 代码是否规范的工具,相比于热度比较高的 Pylint 而言,Flake8检查规则灵活,支持集成额外插件,扩展性强。Flake8 是对下面三个工具的封装

  • PyFlakes:静态检查Python代码逻辑错误的工具。
  • Pep8: 静态检查PEP8编码风格的工具。
  • NedBatchelder’s McCabe :静态分析Python代码复杂度的工具。

hooks (钩子)表示在被特定的时间(certain points)触发后调用。比如说当 git init 命令调用后,一些特定的命令会被执行。

pre-commit hooks 是 git 本地提交前会被执行的一个回调,通过我们定义的脚本可以达到之前提及到的代码格式检查的目的,但凡不符合规范的提交,一律驳回。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/bin/bash

set -e

filesToFormat="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.py/ { print $2}')"

echo "files to format $filesToFormat"

for sourceFilePath in $filesToFormat
do
  isort "$(pwd)/$sourceFilePath" --profile black --honor-noqa --atomic 
  black -l 100 "$(pwd)/$sourceFilePath"
  flake8 "$(pwd)/$sourceFilePath"
  git add $sourceFilePath
done;

exit 0

这个脚本也比较简单,是对于上述工具包的使用。

常见的 commit 的类别,只允许使用以下的标识:

(这个貌似更加合理)

1
2
3
4
5
6
7
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
  • build
  • ci
  • docs
  • feat 新功能(feature)
  • fix 修补bug
  • perf
  • test 增加测试