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 ## 可以查看本地仓库和本地远程仓库(远程仓库的本地镜像) 的所有分支
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 reset
和 git 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 reset
把 HEAD
指向刚刚下载的最新的版本
本地仓库覆盖远程的方法
首先,我远程仓库的 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 中的效果:
修改窗口样式
修改 ~/.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 的人来检查或者集成所修改的。它会输出最近提交的修改内容到一个 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 上面工作,那么您很有可能会经常用到 fetch
和 merge
。但是有时候这样会重置您的环境配置文件,如此的话,您就得在每次 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'