Git

相对位置

除了使用 commit id 作为绝对路径外,Git 还支持三种相对路径:-, ^ 和 ~

  • - 用来表示刚刚的 commit id

  • ~ 表示 commit id 前的某个 commit

例如

git checkout 6feba~2 表示 6feba 前两个 commit

常用命令

  • 远程强制覆盖本地:

    git fetch --all &&  git reset --hard origin/master && git pull
    
  • 本地强制覆盖远程:

    git push origin master --force
    
  • 查看两个版本的差异:

    git diff ba9f93 f6a6ae
    
  • 查看指定文件的版本历史:

    git log conf.py
    
  • 回退到指定版本:

    git reset --hard ba9f93
    
  • 回退文件到指定版本:

    git reset ba9f93 conf.py
    git checkout
    
  • 更改子模块的上游仓库

    1. 直接修改 .gitmodules 文件
    2. 运行 git submodule sync
    
  • 下载指定文件夹的数据

    1. 复制链接,并将 tree/master 替换为 trunk
    2. svn co https://github.com/Mooophy/Cpp-Primer/trunk/ch03
    
  • 取消暂存

    git reset HEAD path
    

合并多个项目

需要将一个项目添加到另一个项目的子路径下,同时保存项目的 commit 历史

# Assume the current directory is where we want the new repository to be created
# Create the new repository
git init

# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit
git commit --allow-empty -m "Initial dummy commit"

# Add a remote for and fetch the old repo
# (the '--fetch' (or '-f') option will make git immediately fetch commits to the local repo after adding the remote)
git remote add --fetch old_a <OldA repo URL>

# Merge the files from old_a/master into new/master
git merge old_a/master --allow-unrelated-histories

# Move the old_a repo files and folders into a subdirectory so they don't collide with the other repo coming later
mkdir old_a
dir -exclude old_a | %{git mv $_.Name old_a}

# Commit the move
git commit -m "Move old_a files into subdir"

# Do the same thing for old_b
git remote add -f old_b <OldB repo URL>
git merge old_b/master --allow-unrelated-histories
mkdir old_b
dir –exclude old_a,old_b | %{git mv $_.Name old_b}
git commit -m "Move old_b files into subdir"

将更改提交到新的分支上

//步骤1:在当前的develop分支上的修改暂存起来
git stash
//步骤2:暂存修改后,在本地新建分支(develop_backup为新分支的名字)
git checkout -b develop_backup
//步骤3:将暂存的修改放到新建分支中
git stash pop
//步骤4:使用命令进行常规的add、commit步骤
git add.
git commit -a "修改内容"
//步骤5:将提交的内容push到远程服务器(在远程也同步新建分支develop_backup)
git push origin develop:develop_backup

合并部分文件

将分支 B 中的部分文件或文件夹合并到分支 A 上

git checkout A
git checkout B public/** view/index.html

合并部分 commit

合并指定分支的某个 commit 到另一分支

git cherry-pick commit_id

本地强制覆盖远程和远程强制覆盖本地

代码为

git push --force
git pull --rebase

撤销 commit

如果想撤销某次 commit,可以使用

git reset --soft commit_id
git reset --hard commit_id

两者的区别是 soft 只是撤销了 commit_id,更改的代码会保留到 暂存区

撤销代码更改

使用下面代码可以撤销当前工作区的更改

git restore .

删除子模块

执行:

git submodule deinit -f module_name
git rm --cached module_name

子模块的使用

Git 在添加子模块后会将子模块固定到特定的 commit_id 上,主代码库中不会显示发生在子模块中的更改。

如果克隆时忘记克隆子模块,只需要执行

git submodule update --init --recursive

如果需要更新子模块到更新的 id 上,执行

git submodule update --remote
git submodule update --remote --merge

区别是第二种会使用远程覆盖掉本地的更改。

然后在主代码库中执行

git add .
git commit

有时候我们需要在子模块中更改代码,然后提交到上游,只需要在子模块路径下

git checkout master
# do some changes
git add .
git commit
git push

然后在主仓库中正常提交即可

撤销暂存

在添加文件后,使用以下命令撤销暂存

git reset HEAD files

修改 commit 信息和添加新文件到上个 commit

命令分别为

git commit --amend
git add files
git commit --amend

git pull

有时候 git pull 会失败。这时候只需要执行

git merge

并解决冲突即可

另外,git pull 相当于 git fetch + 快速合并

此问题的根本原因是上游代码发生了更改,然后下游在没有拉取代码的前提下又产生了新的 commit

撤销指定行

有些时候我们可能需要撤销指定行,使用

git checkout -p

代码提交

在使用 CVS 提交代码时,应当遵循相关的规范以方便后期的查看,这种方式被成为 约定式提交

消息格式 1

每个提交消息都包含一个标题、一个正文和一个页脚。标题包括了类型、范围和主题:

标题是必须的,但是范围是可选的。

提交消息的任何一行都不应当超过一百个字符。

撤销

如果提交还原了之前的提交,它应该以 revert: 开头,后跟还原提交的标题。在正文中,它应该说:This reverts commit <hash>.,其中 hash 是被还原的提交的 SHA。

类型

必须是以下之一:

  • feat: 新功能

  • fix: bug 修复

  • docs: 仅文档更改

  • style: 不影响代码含义的更改(空格、格式、缺少分号等)

  • refactor: 既不修复错误也不添加功能的代码更改

  • perf: 提高性能的代码更改

  • test: 添加缺失的或纠正现有的测试

  • chore: 对构建过程或辅助工具和库(例如文档生成)的更改

范围

范围可以是指定提交更改位置的任何内容。例如$location, $browser,$compile,$rootScope,ngHref,ngClick,ngView,等…

您可以 * 在更改影响多个范围时使用。

主题

该主题包含对更改的简洁描述:

  • 使用祈使句。现在时:“change”而不是“changed”也不是“changes”

  • 不要大写第一个字母

  • 末尾没有点 (.)

正文

就像在主语中一样,使用祈使句,现在时:“change”不是“changed”也不是“changes”。正文应包括改变的动机,并将其与以前的行为进行对比。

页脚

页脚应包含有关重大更改的任何信息,也是 引用此提交关闭的 GitHub 问题 的地方。

Breaking Changes 应该以 BREAKING CHANGE: 带有空格或两个换行符的单词开头。提交消息的其余部分然后用于此。

可以在 本文档 中找到详细说明。

1

angular/DEVELOPERS.md#commits

使用 commitizen 规范提交

安装:

sudo pip3 install -U Commitizen

提交:

cz commit

集成到 Pre-commit

集成到 pre-commit 允许你在提交时使用 cz check 检查提交的信息是否正确。

创建 .pre-commit-config.yaml 文件并添加以下内容

---
repos:
- repo: https://github.com/commitizen-tools/commitizen
   rev: master
   hooks:
      - id: commitizen
      stages: [commit-msg]

运行命令:

pip install pre-commit
pre-commit install --hook-type commit-msg

WSL 中的 GPG 签名

  1. 安装 Gpg4Win

  2. 修改 ~/.gnupg/gpg-agent.conf 并追加以下内容:

    pinentry-program "/mnt/c/Program Files (x86)/Gpg4win/bin/pinentry.exe"
    
  1. 重启 GPG 代理

    gpg-connect-agent reloadagent /bye
    

另外,.gnupg 目录的权限默认为 700,而文件的权限则为 600

GPG 签名问题

出现错误

gpg: 签名时失败: 对设备不适当的 ioctl 操作
gpg: [stdin]: clear-sign failed: 对设备不适当的 ioctl 操作

解决方式

echo "pinentry-program /usr/bin/pinentry-curses" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent

项目提交规范

如果一个项目被放到了开源项目,抑或是你想要提交 PR,有以下几点需要注意:

  • submodule 不要使用 ssh 链接。这样会导致没有私钥的机器无法 clone 项目

  • 提交时注意消息规范。比如有些组织要求对 commit 进行签名

    Author: cathaysia <DragonBillow@outlook.com>
    Date:   Thu Mar 17 13:45:34 2022 +0800
    
       feat(v2): add Update method for v2.Manager
    
       Signed-off-by: LongtaoZhang <DragonBillow@outlook.com>
    
  • 提交时切记先提交 submodule,再提交主仓库。否则主仓库会引用不存在的链接,导致其他人 clone 失败

另外可能还需要注意一些行话: LGTM : code review 行话 - 简书