从 Git 官网下载来的安装包有两种,一种是常规的安装包 Standalone Installer,双击启动安装程序;另一种是处解压安装包 Portable ("thumbdrive edition"),这个程序启动后会把 Git 解压到指定目录,由用户自己完成其它步骤。
第一种只需要不断点下一步即可,而后一种则有些坑:如果使用默认配置,那么在一些旧系统上(比如 Windows Server 2012 R2)可能不能完成 SSL/TLS 加密过程。报错为:
fatal: unable to access 'https://gitea.lishouzhong.com/ld/ld-rime.git/': schannel: next InitializeSecurityContext faile
: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake
failed). More detail may be available in the Windows System event log.
原因是,PortableGit 默认使用了 Windows 上的 schannel 而不是 openssl。要解决这个问题只需要让 Git 使用 openssl 完成 SSL/TLS 加密即可。
如果只对当前用户配置,需要执行 git config --global http.sslBackend openssl
或在用户家目录下的 .gitconfig 中加入以下内容即可:
[http]
sslBackend = openssl
如果想要让这个配置对所有用户生效,则需要把上述配置加入 Git 安装目录中的 PortableGit/etc/gitconfig 文件,最后改完的文件长这样:
[core]
symlinks = false
autocrlf = true
fscache = true
[color]
interactive = true
ui = auto
[help]
format = html
[diff "astextplain"]
textconv = astextplain
[rebase]
autosquash = true
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
[credential]
helper = helper-selector
[http]
sslBackend = openssl
一些仓库要挂代理才能被 git clone
,下面是配置全局代理的命令:
git config --global http.proxy http://127.0.0.1:10801
git config --global https.proxy http://127.0.0.1:10801
git config --global http.proxy socks5://127.0.0.1:10808
git config --global https.proxy socks5://127.0.0.1:10808
下面是只针对某个地址设置代理的命令:
git config --global http.https://github.com.proxy socks5://127.0.0.1:10800
git config --global http.https://github.com.proxy http://127.0.0.1:10801
git rebase -r --root --exec "git commit --amend --no-edit --reset-author"
git push <remote-name> --delete <branch-name>
操作从第一个 commit 开始的所有 commit:
git rebase --interactive --root
从指定 id 的 commit 开始操作:
git rebase --interactive <commit-id>
有两种工作方式,参数带路径和不带路径。
git checkout <commit-or-branch>
用于切换到某个提交或分支的引用。这个操作对工作区的数据安全。 命令的行为是:
对于工作区和暂存区来说:
git checkout <commit-id> </path/to/file>
用于将工作区或/和暂存区的数据恢复到某个历史版本。
不移动 HEAD 指针。这个操作对工作区的数据不安全。 它会从 <commit-id>
中找到指定文件的快照,将其 覆盖 到工作区与暂存区。 若工作区或/和暂存区存在对该文件的更改,则更改会被丢弃。
git checkout -- <filename>
用于将工作区的文件恢复到上一次快照时的状态。 不移动 HEAD 指针。这个操作对工作区的数据不安全。 此时:
注: --
表示该符号之后的字符串将不会被解析成参数。
switch 命令专门用于切换分支,可以用来替代 checkout 的部分用途。
git switch -c <new-branch>
创建并切换到指定分支。
git switch <branch>
切换到已有分支。
和 checkout 一样, switch 对工作区是安全的,它会尝试合并本地数据 (工作区和暂存区的数据) 和文件快照,如果无法合并则中止操作,回到命令执行之前的状态。
git reset <commit-id>
的主要作用是让 HEAD 指针指向特定的 commit。
与 checkout 的区别在于,它对提交历史的更改并不仅仅只是更新 HEAD 本身,如果 HEAD 原来指向某个分支引用 (比如 master 分支),则会将分支引用 (master) 也指向该 commit。
主要了解三个参数:
如果 HEAD 指针指向 master,则命令执行后 HEAD 依然指向 master,但是 master 指向指定的 commit。
如果 HEAD 指针直接指向某个 commit,则 master 不改变指向,HEAD 指针重新指向指定的 commit。
它不会对暂存区和工作区的数据做任何修改。
是默认选项。 git reset --mixed <commit-id>
等同于 git reset <commit-id>
它在 --soft 所做操作的基础上,再把 HEAD 指针指向的 commit 快照 覆盖 到暂存区。
它不会对工作区的数据做任何修改。
所以可以用 git reset HEAD <filename>
把某个文件快照从暂存区中删除 (unstage)。
reset 操作的带文件路径的完整形式是: git reset [<tree-ish>] <pathspec>
该操作的实质是从 <tree-ish>
提取 <pathspec>
(某个文件) 对应的快照覆盖到暂存区。 <tree-ish>
可以是 commit 或分支,默认值 HEAD,所以可以实现从暂存区删除指定文件快照的效果。
这个操作对工作区的数据不安全。
它在 --mixed 所作操作的基础上,再把 HEAD 指针指向的 commit 快照 覆盖 到工作区。工作区和暂存区中所有未提交的更改都会永久丢失。
reset 后丢失的提交历史仍然能够恢复,因为被更新的只有 HEAD 指针,没有对实际的提交对象做任何更改。可以通过 git reflog
找到 HEAD 曾经指向过的 commit ID 后再 git reset --hard <commit-id>
回到该 commit 上。
restore 命令用于还原工作区,或工作区和暂存区中的指定文件或文件集合,格式为:
git restore [--source=<tree>] [--staged] [--worktree] <pathspec>…
--source
参数指定某个 commit ID,默认值是 HEAD 指针指向的 commit<pathspec>
指定一个或多个文件--staged
和 --worktree
两个参数:
--worktree
对工作区生效--staged
对暂存区生效--worktree --staged
用 --source
参数指定的 commit 覆盖工作区和暂存区--worktree
参数是默认值,可以不写--staged
参数被指定时,默认的 --worktree
参数不生效它不会移动 HEAD 指针。这个操作对工作区的数据不安全。
git restore [--source=<tree-ish>] --staged <pathspec>...
等同于 git reset [<tree-ish>] <pathspec>
。较新版本的 Git 会在命令行中提示使用 restore 命令来取消暂存或丢弃工作区的改动。
它用于撤销已被 commit 的数据。
checkout 和 reset 命令会将 HEAD 指针或分支引用重新指向指定的 commit,而 revert 会将指定 commit 在当前分支上重新提交一次。这个操作对工作区的数据安全。
命令的行为是:
比如 git revert <commit2>
会有如下效果:
...<-[commit1]<-[commit2]<-[commit3]<-master<-HEAD
$ git revert <commit2>
...<-[commit1]<-[commit2]<-[commit3]<-[commit2]<-master<-HEAD
要删除的总共有 5 个地方:
其实,删除前 4 个之后,子模块实质上就已经被删除了。此时查看 git status
会发现这样的记录:
new file: <path/to/module>
deleted: <path/to/module>
意思是,这个文件在 git module add
的时候被加入到暂存区,多出一条 new file 记录;然后这个文件又被删除,又多了一条 deleted 记录。
但如果不删除依旧保存在暂存区中的,已经被删除的子模块的记录,会导致无法重新添加这个子模块 (因为暂存区有这个子模块的记录)。所以必须先从暂存区删除这个子模块的记录,才能重新添加这个子模块。
手动删除流程:
git rm --cached path/to/submodule
rm -rf .git/modules/<path/to/submodule>
rm -rf path/to/submodule
注意,如果把 git rm --cached ...
放在最后做,则 git 会提示要先把 .gitmodules 文件加入暂存区才能进行下一步操作。
git submodule deinit -f path/to/submodule
可以清空子模块的工作区,但保留工作区目录。