Skip to content

Git Guide

git 常用指令的用法

  • git remote -v :指查看远程关联的仓库,包括源文件和上一层源文件。
  • git remote add origin + 网址:指添加一个源文件。
  • git remote add upstream + 网址:指添加一个上一层源文件,即 fork 项目的源文件。
  • git remote remove origin/upstream + 网址:指删除一个源文件或上一层源文件。

初始化

  • git clone + 网址:指把网址中对应的项目克隆到自己本机上。
  • git init:指初始化。git 文件,里面没有链接信息,初始化后要重新建立与远程仓库的关联。
  • git pull upstream master:指把获得原项目更新。

提交

  • git add + 文件名:指把修改的某个文件添加到暂存区(指。git 仓库);
  • git add . : 指把所有的修改文件添加到暂存区;
  • git commit -m "认真写为什么要做这次提交":便于日后查阅和他人理解;
  • git push -u origin master: 指把暂存区的文件提交到 github 中。
  • git log:指查看提交的历史记录。
  • dir:查看该文件的子目录。

分支

  • git status:查看所有情况;
  • git branch:指查看分支信息;
  • git branch + 分支名:指创建新的分支;
  • git checkout + 分支名:指切换分支。

如何在忽略本地变化的同时 pull

sh
git pull --rebase --autostash
sh
git fetch --all
git reset --hard origin/master
git pull origin master

Git 五种状态间的顺序操作

四个区

工作区 (Working Area) 暂存区 (Stage) 本地仓库 (Local Repository) 远程仓库 (Remote Repository)

五种状态

未修改 (Origin) 已修改 (Modified)& 未追踪 (Untracked) 已暂存 (Staged) 已提交 (Committed) 已推送 (Pushed)

顺序操作

第零步:工作区与仓库保持一致 第一步:文件增删改,变为已修改状态 第二步:git add ,变为已暂存状态

sh
$ git add --all ## 当前项目下的所有更改
$ git add .  ## 当前目录下的所有更改
$ git add xx/xx.py xx/xx2.py  ## 添加某几个文件

第三步:git commit,变为已提交状态

sh
$ git commit -m"《这里写 commit 的描述》"

第四步:git push,变为已推送状态

sh
$ git push -u origin master ## 第一次需要关联上
$ git push ## 之后再推送就不用指明应该推送的远程分支了
$ git branch ## 可以查看本地仓库的分支
$ git branch -a ## 可以查看本地仓库和本地远程仓库(远程仓库的本地镜像) 的所有分支

title

Git 五种状态间的撤销操作

已修改,但未暂存

sh
$ git diff ## 列出所有的修改
$ git diff xx/xx.py xx/xx2.py ## 列出某(几) 个文件的修改

$ git checkout ## 撤销项目下所有的修改
$ git checkout . ## 撤销当前文件夹下所有的修改
$ git checkout xx/xx.py xx/xx2.py ## 撤销某几个文件的修改
$ git clean -f ## untracked 状态,撤销新增的文件
$ git clean -df ## untracked 状态,撤销新增的文件和文件夹

## Untracked files:
##  (use "git add <file>..." to include in what will be committed)
#
#	xxx.py

已暂存,未提交

这个时候已经执行过git add,但未执行git commit,但是用git diff已经看不到任何修改。

因为git diff检查的是工作区与暂存区之间的差异。

sh
$ git diff --cached ## 这个命令显示暂存区和本地仓库的差异

$ git reset ## 暂存区的修改恢复到工作区
$ git reset --soft ## 与 git reset 等价,回到已修改状态,修改的内容仍然在工作区中
$ git reset --hard ## 回到未修改状态,清空暂存区和工作区

git reset --hard 操作等价于 git resetgit checkout 2 步操作

已提交,未推送

执行完 commit 之后,会在仓库中生成一个版本号 (hash 值),标志这次提交。之后任何时候,都可以借助这个 hash 值回退到这次提交。

sh
$ git diff <branch-name1> <branch-name2> ## 比较 2 个分支之间的差异
$ git diff master origin/master ## 查看本地仓库与本地远程仓库的差异

$ git reset --hard origin/master ## 回退与本地远程仓库一致
$ git reset --hard HEAD^ ## 回退到本地仓库上一个版本
$ git reset --hard <hash code> ## 回退到任意版本
$ git reset --soft/git reset ## 回退且回到已修改状态,修改仍保留在工作区中。

慎用,一般情况下,本地分支比远程要新,所以可以直接推送到远程,但有时推送到远程后发现有问题,进行了版本回退,旧版本或者分叉版本推送到远程,需要添加 -f 参数,表示强制覆盖。

Git 中的那些强制(危险)操作

这些是版本管理的禁术,切勿滥用!

放弃本地所有修改,强制更新

sh
git fetch --all
git reset --hard origin/master

git fetch 只是下载远程的库的内容,不做任何的合并

git resetHEAD 指向刚刚下载的最新的版本

本地仓库覆盖远程的方法

首先,我远程仓库的 config 文件里设置过如下内容(默认新建的 git 仓库是不允许被修改的,所以这里放开修改权限):

sh
[receive]
denyCurrentBranch = ignore
denyNonFastforwards = false ## change to false to enable overwriting

其次,执行如下命令,用本地文件直接覆盖远程仓库:

sh
git push origin branch-name --force

删除 git 仓库中的文件

(从所有历史中清除,不留痕迹)【不可恢复】

sh
## 不可恢复的操作,慎用,一般用来减少仓库体积
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <fileName>'
rm -rf .git/refs/original/*
git reflog expire --expire=now --all
git fsck --full --unreachable
git repack -A -d
git gc --aggressive --prune=now

不支持 ssh-rsa 的解决方案 (2023-09-17)

错误提示

Unable to negotiate with **** port 22: no matching host key type found. Their offer: ssh-rsa fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

这种情况的原因就是新的 ssh 客户端不支持 ssh-rsa 算法,要修改本地配置重新使用 ssh-rsa 算法。

编辑 .ssh/config 文件:

ini
Host *
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

Git 中启用大小写敏感

首先切换到仓库目录

可以通过 git config --get core.ignorecase 查看默认配置

通过 git config core.ignorecase false 设置为区分大小写

使用 VSCode 作为 diff 和 merge 的工具

ini
[difftool "Visual Studio Code"]
	cmd = \"/Applications/Visual Studio Code.app/Contents/MacOS/Electron\" --wait --diff \"$LOCAL\" \"$REMOTE\"
[diff]
	tool = Visual Studio Code
[mergetool "Visual Studio Code"]
	cmd = \"/Applications/Visual Studio Code.app/Contents/MacOS/Electron\" --wait \"$MERGED\"
[merge]
	tool = Visual Studio Code

Git 代理配置

HTTP/HTTPS 代理

当 Git 使用 HTTP/HTTPS 代理时可修改 .gitconfig

ini
[http]
	proxy = http://127.0.0.1:7890
	sslVerify = false
[https]
	proxy = http://127.0.0.1:7890
	sslVerify = false

也可通过命令来修改:

sh
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy https://127.0.0.1:7890

只对 github 生效的代理

sh
git config --global http.https://github.com.proxy https://127.0.0.1:7890
git config --global https.https://github.com.proxy https://127.0.0.1:7890

对应的配置文件是:

ini
[http "https://github.com"]
	proxy = https://127.0.0.1:7890
  sslVerify = false
[https "https://github.com"]
	proxy = http://127.0.0.1:7890
	sslVerify = false

socks5 代理

sh
git config --global http.https://github.com.proxy socks5://127.0.0.1:7890
git config --global https.https://github.com.proxy socks5://127.0.0.1:7890

取消代理

sh
git config --global --unset http.proxy
git config --global --unset https.proxy

SSH 代理 (2023-09-17)

当 Git 使用 SSH 代理时可修改 .ssh/config

Host github.com
  User git
  ProxyCommand connect -S 127.0.0.1:7890 -a none %h %p
  Port 443
  Hostname ssh.github.com
  TCPKeepAlive yes

参考链接:https://gist.github.com/chenshengzhi/07e5177b1d97587d5ca0acc0487ad677

Windows 下的 Git Bash 美化

windows 下的 bash 真的很丑,我尝试美化了一下。

美化终端前缀

修改 C:\Git安装目录\etc\profile.d\git-prompt.sh

sh
if test -f /etc/profile.d/git-sdk.sh
then
	TITLEPREFIX=SDK-${MSYSTEM#MINGW}
else
	TITLEPREFIX=$MSYSTEM
fi

if test -f ~/.config/git/git-prompt.sh
then
	. ~/.config/git/git-prompt.sh
else
	PS1='\[\033]0;Bash\007\]'      # 窗口标题
	PS1="$PS1"'\[\033[32;1m\]'     # 高亮绿色
	PS1="$PS1"'➜ '                 # unicode 字符,右箭头
	PS1="$PS1"'\[\033[33;1m\]'     # 高亮黄色
	PS1="$PS1"'\W'                 # 当前目录
	if test -z "$WINELOADERNOEXEC"
	then
		GIT_EXEC_PATH="$(git --exec-path 2>/dev/null)"
		COMPLETION_PATH="${GIT_EXEC_PATH%/libexec/git-core}"
		COMPLETION_PATH="${COMPLETION_PATH%/lib/git-core}"
		COMPLETION_PATH="$COMPLETION_PATH/share/git/completion"
		if test -f "$COMPLETION_PATH/git-prompt.sh"
		then
			. "$COMPLETION_PATH/git-completion.bash"
			. "$COMPLETION_PATH/git-prompt.sh"
			PS1="$PS1"'\[\033[36m\]'  # change color to cyan
			PS1="$PS1"'`__git_ps1`'   # bash function
		fi
	fi
	PS1="$PS1"'\[\033[0m\]'        # change color
	PS1="$PS1"'\n'                 # new line
	PS1="$PS1"'$ '                 # prompt: always $
fi

MSYS2_PS1="$PS1"               # for detection by MSYS2 SDK's bash.basrc

# Evaluate all user-specific Bash completion scripts (if any)
if test -z "$WINELOADERNOEXEC"
then
	for c in "$HOME"/bash_completion.d/*.bash
	do
		# Handle absence of any scripts (or the folder) gracefully
		test ! -f "$c" ||
		. "$c"
	done
fi

修改后在 VSCode 中的效果:

git-bash__2023-09-27-21-29-51

修改窗口样式

修改 ~/.minttyrc

ini
Font=Consolas
FontHeight=10

ForegroundColour=131,148,150
BackgroundColour=40,44,52
CursorColour=82,139,255

Black=40,44,52
BoldBlack=90,44,52
Red=224,108,117
BoldRed=255,108,117
Green=152,195,121
BoldGreen=152,245,121
Yellow=229,192,123
BoldYellow=229,192,173
Blue=97,175,239
BoldBlue=97,175,255
Magenta=198,120,221
BoldMagenta=248,120,221
Cyan=86,182,194
BoldCyan=86,232,194
White=171,178,191
BoldWhite=231,178,191
BoldAsFont=-1
FontSmoothing=full
FontWeight=700
Locale=C
Charset=UTF-8
Columns=80
Rows=28

修改后的效果:

git-bash__2023-09-27-21-31-28

输出最后一次提交的改变

这个命令,我经常使用它 来发送其他没有使用 git 的人来检查或者集成所修改的。它会输出最近提交的修改内容到一个 zip 文件中。

sh
git archive -o ../updated.zip HEAD $(git diff --name-only HEAD^)

输出两个提交间的改变

类似的,如果你需要输出某两个提交间的改变时,你可以使用这个。

sh
git archive -o ../latest.zip NEW_COMMIT_ID_HERE $(git diff --name-only OLD_COMMIT_ID_HERE NEW_COMMIT_ID_HERE)

克隆 指定的远程分支

如果你渴望只克隆远程仓库的一个指定分支,而不是整个仓库分支,这对你帮助很大。

sh
git init
git remote add -t BRANCH_NAME_HERE -f origin REMOTE_REPO_URL_PATH_HERE
git checkout BRANCH_NAME_HERE

应用 从不相关的本地仓库来的补丁

如果你需要其它一些不相关的本地仓库作为你现在仓库的补丁,这里就是通往那里的捷径。

sh
git --git-dir=PATH_TO_OTHER_REPOSITORY_HERE/.git format-patch -k -1 --stdout COMMIT_HASH_ID_HERE| git am -3 -k

检测 你的分支的改变是否为其它分支的一部分

cherry 命令让我们检测你的分支的改变是否出现在其它一些分支中。它通过 + 或者 - 符号来显示从当前分支与所给的分支之间的改变:是否合并了 (merged)。.+ 指示没有出现在所给分支中,反之,- 就表示出现在了所给的分支中了。这里就是如何去检测:

sh
git cherry -v OTHER_BRANCH_NAME_HERE
#例如:检测 master 分支
git cherry -v master

开始一个无历史的新分支

有时,你需要开始一个新分支,但是又不想把很长很长的历史记录带进来,例如,你想在公众区域(开源)放置你的代码,但是又不想别人知道它的历史记录。

sh
git checkout --orphan NEW_BRANCH_NAME_HERE

无切换分支的从其它分支 Checkout 文件

不想切换分支,但是又想从其它分支中获得你需要的文件:

sh
git checkout BRANCH_NAME_HERE -- PATH_TO_FILE_IN_BRANCH_HERE

忽略已追踪文件的变动

如果您正在一个团队中工作,而且大家都在同一条 branch 上面工作,那么您很有可能会经常用到 fetchmerge。但是有时候这样会重置您的环境配置文件,如此的话,您就得在每次 merge 后修改它。使用这一命令,您就能要求 git 忽视指定文件的变动。这样,下回你再 merge 的话,这个文件就不会被修改了。

sh
git update-index --assume-unchanged PATH_TO_FILE_HERE

检查提交的变动是否是 release 的一部分

name-rev 命令能告诉您一个 commit 相对于最近一次 release 的位置。使用这条命令,您就可以检查您所做出的改动是否是 release 的一部分了。

sh
git name-rev --name-only COMMIT_HASH_HERE

使用 rebase 推送而非 merge

如果您正在团队中工作并且整个团队都在同一条 branch 上面工作,那么您就得经常地进行 fetch/merge 或者 pull。 Git 中,分支的合并以所提交的 merge 来记录,以此表明一条 feature 分支何时与主分支合并。 但是在多团队成员共同工作于一条 branch 的情形中,常规的 merge 会导致 log 中出现多条消息,从而产生混淆。因此,您可以在 pull 的时候使用 rebase,以此来减少无用的 merge 消息,从而保持历史记录的清晰。

sh
git pull --rebase

您也可以将某条 branch 配置为总是使用 rebase 推送:

sh
git config branch.BRANCH_NAME_HERE.rebase true

导出差量更新包

通过git diff得到差异列表

通过git archive打包

sh
git archive -o yourZipName.zip HEAD $(git diff copyID1 copyID2 --name-only)

清理缓存,并更新 gitignore

sh
git rm -r --cached .
git add .
git commit -m 'update .gitignore'

最后编辑时间:

Version 4.2 (core-1.3.4)