Git 其他类型操作

分支重命名

本地

git branch -m <old_branch_name> <new_branch_name> 

远程

  git push origin <new_branch_name> //新建分支
  git push origin -d -f <old_branch_name> //删除旧的分支

回滚

git reset --hard(强制) dhcsdvbhfsjb
git reset dhcsdvbhfsjb

Tag

git tag v1.0.1 #为当前打tag
git push tags #推送tag
git tag #查看tag信息
  • 删除tag
# 当前
git tag -d <tag_name>

# 远程
git push origin --delete <tag_name>

pull警告

git config pull.rebase false

git merge

merge 回退

git reset --merge
git merge --abort

merge前检查冲突

git merge --no-commit

revert和reset区别

  1. revert 生成一次操作相反的commit, 达到回滚的目的

  2. reset直接向前移动指针ref

cherry-pick

  • 作用: 将分支的某一次提交应用到别的分支上

  • 用法

git checkout branch # 切换向改变的分支

git cherry-pick <commitHash> # 提交的hash
or
git cherry-pick <branch>#默认最近的提交

git cherry-pick <HashA> <HashB> # 一次添加多个提交

git cherry-pick <HashA..<HashB> # 一次添加一系列提交

git stash

  • 作用

用于临时保存目前的状态,紧急切换分支

  • 使用
git stash #保存

git stash save "test-cmd-stash" # 添加stash信息

git stash list # 列出

git stash apply # 应用stash

git stash apply stash@{2} # 应用stash

git排序文件大小

git rev-list --objects --all  | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)'  | sed -n 's/^blob //p'  | sort --numeric-sort --key=2  | cut -c 1-12,41-  | $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

删除git已经跟踪文件

删除

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch path-to-your-remove-file' --prune-empty --tag-name-filter cat -- --all

推送

git push origin master --force --all

排序

git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

简单删除

  • git rm --cached readme1.txt    删除跟踪,并保留在本地。

  • git rm --f readme1.txt    删除跟踪,并且删除本地文件。

  • 不会删除以前的提交记录

参考

Checkout检出文件

  • git checkout (commit_id 为空则默认上一次) -- (需要签出文件名)

分区关系图

二分法查错

  • 选定查找范围
git bisect start [终点] [起点]
  • 判定该提交为好/坏
git bisect good/bad

gc

  • 打包一些老的提交以压缩空间
git gc

[!important] 运行这个命令之后默认只会gc 2个星期前的object,而且danging悬空的对象因为有reflog 导致无法被直接删除,如果需要删除悬空对象,需要运行 git gc --prune=0 这个命令的意思是gc从现在开始的对象,以及最开始需要运行 git reflog expire --expire-unreachable=0 --all 这个命令的意思是立刻清空reflog里的所有从当前head不可达对象(unreachable)的引用(reflog entries)。使得gc可以正确运行

fsck

  • 运行 git fsck --lost-found 查找所有的悬空对象

cat-file

  • 查看hash对应obj内容
git cat-file -p 1234
git cat-file -t 1234

删除本地远程分支

git pull --prune

检查是否冲突

git merge --no-commit --no-ff
# 取消
git merge --abort

Git reflog

  • 记录指针每一次发生改变的记录,用于找回分支以及reset hard

Git commit --amend

  • 后面不需要添加任何参数

  • 修改上一次提交的内容(用于这次修改想合并到上一个修改),不能用于已经提交远程的修改

Squash

  • git merge --squash, 合并,但只保存一次提交记录

修改默认远程分支

  • git branch --set-upstream-to=origin/master master

Rebase

  • 在feature中git rebase master,实际上是修改了

操作

解决合并冲突(尽量少用)

# demo
git checkout feat/some-thing
git rebase master
# resolving git conflicts.....
git checkout master
git merge feat/some-thing
  1. 切换分支
  2. rebase master,如上图,将feat分支的base更改为当前的master(实质上是将自己额外的提交拿出来放到当前master的头部),此时新添加的commit会相应的进行合并并生成新的提交记录(和原来的hash不一样,不是同一个提交)
优点
  • 操作简单,方便解决冲突
缺点
  • 多人使用同一分支会出现灾难
  • test环境依旧无法使用,只适用于正式环境

简化提交记录

  • !!一旦推送远程,禁止rebase!!
  • 不推荐使用这个用法,因为很麻烦而且有可能冲突,不如分支合并到master再squash
  1. 查看自己的日志,找到需要合并到的hash
  2. 使用 git rebase -i <commit> 命令进行交互式 rebase,或者git rebase -i HEAD^n (n为需要更改的提交数量)
  3. 编辑窗口需要更改的版本前改成s

远程和本地代码合并

用于本地有提交,远程也有提交,pull下来时候的merge

  1. pull=fetch+merge,因此运行git fetch
  2. 执行git rebase,将本地的commit,拿出来放到远程的头部

禁忌(黄金法则)

  • 不要在已经推送到远程的提交进行rebase!!,
  • 永远不要rebase共享分支,非常容易造成提交丢失

Submodule

[!important] 注意 submodule的路径不要放在ignore里面, 因为是submodule自己管理的

  • 子模块,通过git submodule add <repository-url> <path>添加,添加后会生成.gitmodules文件
[submodule "third_party/googletest"]
	path = third_party/googletest
	url = https://github.com/google/googletest.git
	branch = release
[submodule "third_party/benchmark"]
	path = third_party/benchmark
	url = https://github.com/google/benchmark
  • 通过git clone --recurse-submodules这个命令递归clone
  • 已经拉取的仓库通过git submodule update --init --recursive --depth=1拉取
  • 更新版本需要进入文件夹中主动 git pull

创建

  • git submodule add <model_url>
  • git submodule add -b <branch> <remote> <path> 不指定分支就不传 -b <branch>

拉取

  • git clone url --recurse-submodules

删除

  • git submodule deinit project-sub
  • git rm project-sub
  • 参考

出现'you must specify a branch'

  • pull的时候加上分支,如git pull gitee master

git只回退某个文件或者文件夹

  • 回退文件:git checkout HEAD <file>或者git checkout -- <file>,推荐第一种,这里的HEAD可以直接换成commit-id,这样就是回退到某个地方

  • 回退文件夹git checkout <commit_id> -- <folder_path>

git 命令分页问题

  • git config --global pager.branch false

  • 参考https://blog.csdn.net/albertsh/article/details/114806994

  • 参考

  • 全局设置git config --global core.pager

  • 单个命令设置git config --global pager.branch false

git删除tag

git tag -d <tag_name> #本地tag
git push origin -d <tag_name> # 远程tag

git统计个人代码行数

#!/bin/bash
printf "\n1. 项目成员数量:"; git log --pretty='%aN' | sort -u | wc -l

printf "\n\n2. 按用户名统计代码提交次数:\n\n"
printf "%10s  %s\n" "次数" "用户名"
git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5
printf "\n%10s" "合计";
printf "\n%5s" ""; git log --oneline | wc -l

printf "\n3. 按用户名统计代码提交行数:\n\n"
printf "%28s %18s %18s %18s\n" "用户" "总行数" "添加行数" "删除行数"
git log --format='%aN' | sort -u -r | while read name; do printf "%25s" "$name"; \
git log --author="$name" --pretty=tformat: --numstat | \
awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "%15s %15s %15s \n", loc, add, subs }' \
-; done

printf "\n"
printf "\n%25s   " "总计:"; git log --pretty=tformat: --numstat | \
awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "%15s %15s %15s \n", loc, add, subs }'

[!tip] 参考 https://cloud.tencent.com/developer/article/2087250

git/ssh 设置代理

[!tip] 参考 https://ericclose.github.io/git-proxy-config.html 非常详细

http/https

git config http.proxy http://127.0.0.1:7890
git config http.proxy socks5://127.0.0.1:7891

ssh

这部分也可以用作ssh连接的代理 如果ssh push不上去可以试着把 .ssh/config 里面github内容注释掉 可以先用 ssh -T git@github.com 检测是否能够连接

  1. 编辑~/.ssh/config
Host github.com
    User git
    ProxyCommand nc -X 5 -x 127.0.0.1:7891 %h %p

# `%h` 和 `%p` 将会被自动替换为**目标主机名**和 **SSH 命令指定的端口**
# -X 是指定默认socket5,不指定也可以
  • 或者,SSH连接的代理
# 如果代理服务器需要认证,可以使用 nc 的升级版 ncat 指定代理服务器的用户名和密码
ssh -o ProxyCommand="ncat --proxy-type http/socks4/socks5 --proxy proxy.net:port --proxy-auth proxyuser:proxypwd %h %p" user@server.net

[!tip] 出任何问题看参考文章,很详细

git打包代码压缩包

git archive --output=<output-path>.zip HEAD
# or
git archive --output=<output-path>.tar HEAD

git LF的问题

  • 参考# window git crlf lf 换行符问题

    // 提交时转换为LF,检出时转换为CRLF
    git config --global core.autocrlf true
    
    // 提交时转换为LF,检出时不转换
    git config --global core.autocrlf input
    
    // 提交检出均不转换
    git config --global core.autocrlf false
    
    // 拒绝提交包含混合换行符的文件
    git config --global core.safecrlf true
    
    // 允许提交包含混合换行符的文件
    git config --global core.safecrlf false
    
    // 提交包含混合换行符的文件时给出警告
    git config --global core.safecrlf warn
    

    参考

    • https://www.cnblogs.com/hushaojun/p/16001784.html

出现refusing to merge unrelated histories

  • 两个仓库不同而导致的,需要在后面加上--allow-unrelated-histories进行允许合并,即可解决问题
  • 本质上应该并不会出现这个问题(如果是clone的),考录重新clone仓库

出现 error: remote unpack failed: index-pack failed

git 附注标签

  • 实际上就是标签出现注释的内容
  • git tag -a <tag> -m <message>

临时修改提交人员信息

  • git commit --author="Your Name <your@email.com>"

查看某个文件某次提交不同

  • 和当前不同 git diff <commit-id> <file>
  • 两个提交之间不同 git diff <commit-id> <commit-id> <file>

git clone 拉取指定分支

  • git clone -b <branch> <remote_url>

git 分页器

  • 使用某些git 命令会出现新的窗口, 需要 q 才能推出, 使得麻烦(比如branch 和tag)
  • 单独屏蔽某个命令 git config --global pager.branch false
  • 全部屏蔽, 关闭功能 git config --global core.pager ''

[!tip] 参考 解决git命令会将结果输出到单独窗口必须按q才能退出的问题_git config --global core.pager-CSDN博客

设置init默认分支名

  • git config --global init.defaultBranch master master比main好多了, 政治正确是最愚蠢的东西

修改 commiter

  • 单个修改(单个仓库, 全局需要加上 --global
 git config user.name chenxuan
 git config user.email 1607772321@qq.com
  • 批量修改, 改完推远程需要 -f
git filter-branch --env-filter '
OLD_EMAIL="xxx@yyy"
CORRECT_NAME="chenxuan"
CORRECT_EMAIL="1607772321@qq.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

[!tip] 参考 单独或批量修改commit的author信息场景1: 单独修改1个或几个少量commit的author信息。 1.配置正 - 掘金

获取提交的tag信息

  • git describe --tags --always 返回结果如果这个commit 有tag直接返回tag, 否则返回类似 v0.0.9-6-gc314ce1
    • v0.0.9 代表上一个最近的版本
    • 6 代表过去了6个commit
    • g 没什么实际作用, 指示是git
    • c314ce1 代表最近 commit 的 hash值

Svn

目录结构

├── current
├── format
├── fsfs.conf
├── fs-type
├── min-unpacked-rev
├── rep-cache.db
├── rep-cache.db-journal
├── revprops
│   └── 0
│       ├── 0
│       ├── 1
│       └── 2
├── revs
│   └── 0
│       ├── 0
│       ├── 1
│       └── 2
├── transactions
├── txn-current
├── txn-current-lock
├── txn-protorevs
├── uuid
└── write-lock

  • svn记录版本和上一个版本的区别(git直接保存两者)
  • svn 创建分支方法是直接复制一份(git只是创建一个指针)