跳转至

git

git

高级

  • 从一个节点产生多个分支,能否 rebase 新的 cm 到该节点?

reset 后恢复 reflog

git reflog

reset --soft, --mixed, --hard

version control - What's the difference between git reset --mixed, --soft, and --hard? - Stack Overflow

修改的不同阶段:

  • in working directory:
  • index / stagged:通过 git add
  • commited:进入版本控制,commited 的修改总能找回来。
- A - B - C (master)

--soft B:将 C 的修改恢复到 index 中 --mixed B:将 C 的修改恢复到 working directory 中 --hard B:index 被修改为 B,working directory 清空

git co 和 git reset --mixed 效果类似,都能保留当前 working directory,同时还能保留 git log。

rebase

Q: git X 分支有 A, B, C 三个提交,Y 分支有 A, B2 两个提交,如何将 X 分支 rebase 到 B2。其中 B 和 B2 存在冲突 A:

git rebase --onto Y B X
  • Y 是你要将提交移到的分支(即 B2 之后)。
  • B 是你想要忽略的基提交(B 会被替换为 B2)。
  • X 是当前分支。
 git rb --onto local/main ddcfc5d memory
First, rewinding head to replay your work on top of it...
Applying: rewrite PPT-GPU get_max_active_block
Applying: run sim error print output to stderr

Refspec(手动设置 fetch 分支)

clone 仓库时指定了 depth = 1, branch = dev/distributed,后面 git fetch origin 无法获取其他分支

解决方法

0 单次 fetch

不推荐,之后 git pull 仍然无法正常使用

# 语法:git fetch <remote> <source_branch>:<destination_remote_tracking_branch>
git fetch origin dev_4_9_2:refs/remotes/origin/dev_4_9_2

取消浅层克隆

# 下载仓库剩余的所有历史记录,并移除浅层限制
git fetch --unshallow

如果你不想下载所有历史,想开始跟踪其他分支

1 set-branches

git remote set-branches --add origin dev_4_9_2

2 手动修改 .git/config

你可以手动修改 .git/config 文件

[remote "origin"]
fetch = +refs/heads/dev/distributed:refs/remotes/origin/dev/distributed
fetch = +refs/heads/dev_4_9_2:refs/remotes/origin/dev_4_9_2
#fetch = +refs/heads/*:refs/remotes/origin/*

重名/删除 refs

git show-ref dev/distributed

git update-ref -d refs/remotes/dev/distributed

删除 refs/remotes/ 下非 remote 仓库的 refs

#!/bin/bash

# 获取所有已配置的远程仓库名称 (例如: "origin", "local")
remotes=$(git remote)
echo "发现有效的远程仓库: $remotes"
echo "--- 开始查找并删除位置错误的远程引用 ---"

# 遍历 'refs/remotes/'下的所有引用
git for-each-ref refs/remotes/ | while read -r _ _ ref; do
    # 截取掉 "refs/remotes/" 前缀,得到类似 "dev/distributed" 或 "origin/main" 的短名称
    short_ref=${ref#refs/remotes/}

    # 设置一个标记,判断当前引用是否属于一个已知的远程仓库
    is_valid_remote_ref=false

    # 检查短名称是否以 "[remote_name]/" 的形式开头
    for remote in $remotes; do
        if [[ "$short_ref" == "$remote/"* ]]; then
            is_valid_remote_ref=true
            break
        fi
    done

    # 如果引用不属于任何已知远程仓库,那它就是我们要删除的错误引用
    if ! $is_valid_remote_ref; then
        echo "正在删除错误引用: $ref"
        git update-ref -d "$ref"
    fi
done

echo "--- 清理完成 ---"

基础

branch

查看分支 upstream

git br -vv

设置 upstream

git branch --set-upstream-to=origin/dev_4_9_2 dev_4_9_2

重命名

git branch -m foo bar

remote

  • 可以查看仓库的 fetch url 和 push url
  • origin/HEAD,表示仓库的默认分支(用于 git clone 等)
  • 远程仓库的分支
  • 本地仓库配置了 git push 的分支
git show remote origin

tag

#显示所有tag
git tag
#显示具体tag信息
git show v1.2
#添加tag
git tag v1.2 9fceb02 -a
git tag v1.2 9fceb02 -a -m "my tag"
#删除tag
git tag -d v1.2
#推送tag到远程
git push origin --tags

小技巧

查找某个 commit 并显示修改

  • -i 忽略大小写
  • --all 查找所有分支
git log --all --grep="你的搜索关键词" -i
  • --stat 仅显示修改了哪些文件
git show 199bb01d00 --stat

shallow clone

避免 clone 的仓库太大,将 git commit 记录截断。

git clone --depth 1 git://gcc.gnu.org/git/gcc.git

man git-clone Create a shallow clone with a history truncated to the specified number of commits. Implies --single-branch unless --no-single-branch is given to fetch the histories near the tips of all branches. If you want to clone submodules shallowly, also pass shallow-submodules.

代码统计

Git统计代码量和常用命令 - lovezj9012 - 博客园 统计每个人的增删行数

git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s ", add, subs, loc }' -; done

根据时间段排除文件夹统计

git log --since=2021-01-28 --until=2021-02-03 --pretty=tformat: --numstat -- . ":(exclude)src/test" | awk '{ add += $1; subs += $2; loc += $1 + $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }'

-- . ":(exclude)folderName"  folderName指src/test文件夹,这里是相对路径 -- . ":(exclude)folderName1"  ":(exclude)folderName2"  排除多个文件夹 -- . ":(exclude)folderName"也 可以用在其他的统计中;--前只能有一个空格,有多个空格识别不了

移动非当前分支到某个 commit

git branch -f b HEAD

cherry-pick

Q: git 分支 B 想要获得分支 A 上除了某一次提交外的其他5-6个提交,有什么简单的方法。分支 A 和 B 从某个点 C 分叉

Cherry-pick 范围选择

cherry-pick  A..B   # (A, B]
cherry-pick  A^..B  # [A, B],从 A 到 B 所有 commit。^作用是表示 A 的上一个

清除远程已删除的分支

git remote show origin  # 查看远程分支情况,git pull 和 git push 本地分支配置的上游分支
git remote prune origin
git fetch origin -p   # --prune

clean untrack 文件

有时候 git reset 后,会有大量 untrack 的文件

  • -n--dry-run 参数来进行演习
  • -f--force:这是强制执行的意思。如果没有这个参数,Git 不会真的删除文件,而是会提示您使用 -f 来确认。这是一个安全措施,防止您意外删除重要文件。
  • -d:这个参数表示连同未被追踪的目录一起删除。如果您只想删除文件而不删除目录,可以省略这个参数。
git clean -nd  # dry-run 测试一下
git clean -fd

代理

查看详细信息

  • GIT_TRACE=1
  • git --verbose <cmd>

http 和 https 设置代理


ssh 代理

windows

windows 下没有 nc 命令,需要 connect.exe(可以下载.c 文件编译成 exe 文件)

SSH in git behind proxy on windows 7 - Stack Overflow

Host github.com
  HostName github.com
  ...
  ProxyCommand connect -H 127.0.0.1:11223 %h %p

遇到的问题

unsafe directory

git - Fatal error "unsafe repository ('/home/repon' is owned by someone else)" - Stack Overflow

git version > Git 2.36

git config --global --add safe.directory '*'

curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8)

➜  repo git clone https://github.com/YaoFANGUK/video-subtitle-generator
Cloning into 'video-subtitle-generator'...
remote: Enumerating objects: 434, done.
remote: Counting objects: 100% (95/95), done.
remote: Compressing objects: 100% (53/53), done.
error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8)
error: 503 bytes of body are still expected
fetch-pack: unexpected disconnect while reading sideband packet
fatal: early EOF
fatal: fetch-pack: invalid index-pack output

git - error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1) - Stack Overflow

git config --global http.version HTTP/1.1

成功

➜  repo git clone https://github.com/YaoFANGUK/video-subtitle-generator
Cloning into 'video-subtitle-generator'...
remote: Enumerating objects: 434, done.
remote: Counting objects: 100% (95/95), done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 434 (delta 46), reused 87 (delta 42), pack-reused 339
Receiving objects: 100% (434/434), 5.92 GiB | 21.39 MiB/s, done.
Resolving deltas: 100% (149/149), done.
Updating files: 100% (151/151), done.

貌似修改 buffer 也可以:GIT 推送错误 error: RPC failed;curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8) - 郭小睿 - 博客园 (cnblogs.com)

git config --global http.postBuffer 524288000

git cherry-pick allow empty

根据图片显示的信息,"the previous cherry-pick is now empty" 这句话表示​​之前的 cherry-pick 操作最终没有引入任何实际文件变更​​。这种情况通常出现在处理代码冲突时,以下是具体解析:

​坚持提交空操作​​(如需保留提交记录)

git commit --allow-empty

放弃空操作并继续

git reset              # 重置当前cherry-pick操作
git cherry-pick --continue  # 继续处理后续提交
  • 完全跳过此次无效的cherry-pick
  • 推荐选择,避免污染提交历史

patch 补丁

diff, patch 工具

我对 A 文件进行了一些修改得到 B,现在 A 发生了变化,我如何将修改作用在新的 A 上

diff -u A B > A.patch

patch A_new --merge -o B_new < A.patch
patch A_new --merge -o B_new -i A.patch
  • -i: 指定 patch 文件,而不是从 stdin 读入
  • -o:patched 后的文件路径
  • --merge: 将冲突部分写入输出文件(使用 conflict marker),而不是创建单独的 reject 文件
    • conflict 标记就是 git 格式,vscode 中对其会可视化显示

git format-patch

Git 打补丁-- patch 和 diff 的使用(详细) - 掘金 (juejin.cn)

Git 提供了两种补丁方案,一是用 git diff 生成的 UNIX 标准补丁.diff 文件,二是 git format-patch 生成的 Git 专用.patch 文件。 .diff 文件只是记录文件改变的内容,不带有 commit 记录信息,多个 commit 可以合并成一个 diff 文件。 .patch 文件带有记录文件改变的内容,也带有 commit 记录信息,每个 commit 对应一个 patch 文件。

git format-patch HEAD^  # 最新的一次 commit(上一次到现在的 commit)
git format-patch 【commit sha1 id】..【commit sha1 id】 # 某两次提交之间的所有patch
  • -o: If -o is specified, output files are created in dir. Otherwise they are created in the current working directory
  • -n: -n, --numbered Name output in [PATCH n/m] format, even with a single patch.
git am 【path/to/xxx.patch】

git diff 相关

git diff 【commit sha1 id】 【commit sha1 id】 > 【diff文件名】
git diff --no-index file1 file2 # 非git repo下,生成两个文件diff
git apply [--check] 【path/to/xxx.patch
git apply --check 【path/to/xxx.diff】

format-patch

Git - git-format-patch Documentation (git-scm.com)

git format-patch HEAD^  # 最新的一次 commit(上一次到现在的 commit)
git format-patch 【commit sha1 id】..【commit sha1 id】 # 某两次提交之间的所有patch

应用 patch

git am patch/*.patch

# 保留原本提交时间
git am --committer-date-is-author-date patch/*.patch

submodule

可以本地添加 submodule

git submodule add ./third-party/nvbit_release third-party/nvbit_release

添加 submodule 后会生成.gitmodules文件

[submodule "third-party/gpu-rodinia"]
        path = third-party/gpu-rodinia
        url = ./third-party/gpu-rodinia
[submodule "third-party/nvbit_release"]
        path = third-party/nvbit_release
        url = ./third-party/nvbit_release
[submodule "third-party/cuda-samples"]
        path = third-party/cuda-samples
        url = ./third-party/cuda-samples
[submodule "third-party/gpu-parboil"]
        path = third-party/gpu-parboil
        url = ./third-party/gpu-parboil

clone submodule

clone 时默认是不会 clone 子模块的,需要添加 recursive。-j8 表示使用多线程下载。

git clone --recursive -j8 gpu-analysis-model gpu-analysis-model-70

会从.gitmodules中指定的 url 中 clone 仓库,然后 checkout 到对应 commit。如果是本地 commit,没有推送到远程,则会因为没有对应 commit 而报错。解决方法是改用本地仓库作为 url。

git submodule init
git submodule update

# 合并成一个
git submodule update --init --recursive
git submodule update --init --recursive --depth 1
git submodule deinit

file not allowed 问题

Submodule 'third-party/cuda-samples' (/staff/fyyuan/repo/gpu-analysis-model/third-party/cuda-samples) registered for path 'third-party/cuda-samples'

Cloning into '/staff/fyyuan/repo/gpu-analysis-model-70/third-party/cuda-samples'...
fatal: transport 'file' not allowed

解决方法

git config --global protocol.file.allow always

LFS

参考

使用方法

  1. 执行 track 命令建立跟踪 1. 实际修改了 .gitattribute 文件,需要 git add 提交 git commit -m "Add \"*.bigfile\" LFS config "
git lfs track "*.bigfile" # 以`.bigfile`后缀结尾的文件使用Git LFS进行存储

git lfs    # 查看当前已跟踪的Git LFS File 类型
  1. 新建 .bigfile 文件,然后 git add 1. git 实际创建 Git LFS Pointer 文件,包含
    +version https://git-lfs.github.com/spec/v1
    +oid sha256:49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
    +size 1073741824
    

本地的Git LFS文件是如何存储的

  • LFS缓存目录
  • 名称被改为 oid(Git LFS object id)
$tree .git/lfs
.git/lfs
├── objects
    └── 49
         └── bc
             └── 49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
└── tmp
4 directories, 1 file

撤销LFS跟踪并使用Git管理

git lfs untrack "*.bigfile"
git rm --cached "*.bigfile"
git add "*.bigfile"
git commit -m "restore "*.bigfile" to git from lfs"

Git LFS处理流程