Git 笔记 📒

准备工作

安装

官网下载

macOS

1
brew install git

Linux

1
sudo apt-get install git

查看版本信息/是否安装

1
git --version

生成 SSH 密钥

输入 ls -al ~/.ssh 查看是否存在 SSH keys

1
2
ls -al ~/.ssh
# Lists the files in your .ssh directory, if they exist

查看是否生成过 public SSH key。默认情况下 GitHub 支持的 public keys 文件名如下:

  • id_rsa.pub
  • id_ecdsa.pub
  • id_ed25519.pub

若已存在则跳过下面步骤。

Generating a new SSH key and adding it to the ssh-agent

使用 SSH 密钥密码

使用 SSH 密钥时,如果有人获得您计算机的访问权限,他们也可以使用该密钥访问每个系统。 要添加额外的安全层,可以向 SSH 密钥添加密码。 您可以使用 ssh-agent 安全地保存密码,从而不必重新输入。

Working with SSH key passphrases

添加 SSH 密钥

Adding a new SSH key to your GitHub account

1
2
3
cat ~/.ssh/id_ed25519.pub
# Then select and copy the contents of the id_ed25519.pub file
# displayed in the terminal to your clipboard

测试 SSH 连接

1
2
ssh -T git@github.com
# Attempts to ssh to GitHub

可能会看到类似如下的 warning

1
2
3
> The authenticity of host 'github.com (IP ADDRESS)' can't be established.
> RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
> Are you sure you want to continue connecting (yes/no)?

公钥指纹可用于验证与远程服务器的连接。以下是 GitHub 的公钥指纹:

  • SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 (RSA)
  • SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM (ECDSA)
  • SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU (Ed25519)

验证无误后输入yes

1
2
> Hi USERNAME! You've successfully authenticated, but GitHub does not
> provide shell access.

初始化用户信息/更改配置

1
2
3
4
5
git config --global user.email you@example.com
git config --global user.name "Your Name"

git config --global user.email "FacundoChan01@gmail.com"
git config --global user.name "Facundo Chan"

更改配置

1
git config --global -e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# This is Git's per-user configuration file.
1 [https]
2 proxy = socks5://127.0.0.1:7890
3 [http]
4 proxy = socks5://127.0.0.1:7890
5 [user]
6 name = Facundo Chan
7 email = FacundoChan01@gmail.com
8 [core]
9 editor = vim
10 excludesfile = /Users/chan/.gitignore_global
11 [init]
12 defaultBranch = main
13 [color]
14 ui = true

关于 main/master 分支

本地 main/master 分支

GitHub 于 2020 年对默认分支名进行了更改(见Renaming the default branch from master),因此建议将Git默认分支从master修改为main

1
2
# 将 Git 默认分支从 master 修改为 main
git config --global init.defaultBranch main

否则后面输入git push origin main可能出现下列问题,因为 Git 默认的分支为master,没有main分支

1
2
3
git push origin main
error: src refspec main does not match any
error: failed to push some refs to 'github.com:.../....git'

解决办法如下:

1
2
3
4
5
6
7
8
9
10
11
12
# 切换到main分支并进入
git checkout -b main
Switched to a new branch 'main'

# 删除本地的master分支
git branch -D master

# 创建新仓库的时候可能带有README.md文件,而本地没有,所以需要先拉取下来
git pull origin main --allow-unrelated-histories # 老版本:git pull origin main

# 然后就可以push了
git push origin main

GitHub main/master 分支

假设把默认master分支更名为 main分支,此时有个本地 clone,可以通过下面的指令更新仓库。

1
2
3
4
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a

项目管理

使用 Git 初始化本地仓库

1
git init # 初始化本地仓库

GitHub 设置仓库

需要关注以下几个点:

关于README.md

README通常是访客访问仓库第一个看见的文件,内容一般包括但不限于介绍[^ 1]:

  • 这个项目是做什么的?
  • 为什么这个项目有用?
  • 如何着手使用该项目?
  • 从该项目能获得什么帮助?
  • 项目维护和贡献者。

如何规范书写 ✍️README.md

Concise, consistent, and legible badges

关于.gitignore

.gitignore是一个文本文件,它告诉 Git 要忽略项目中的哪些文件或文件夹。详细查看 .gitignore章节。

创建全局.gitignore

创建全局.gitignore文件,以定义忽略本机上每个 Git 存储库中文件的规则列表。 例如,在 ~/.gitignore_global 中创建文件并在其中加入一些规则。

配置 Git 对所有 Git 存储库使用排除文件 ~/.gitignore_global

1
git config --global core.excludesfile ~/.gitignore_global

关于Liicense的选择

如何选择合适的 License?

本地设置远程仓库

GitHub 官方文档

Git Basic - Working with Remotes

首先确保已使用 Git 初始化本地仓库,然后添加远程仓库:

The command takes two arguments:

  • A remote name, for example, origin
  • A remote URL, for example,
1
git remote add origin https://github.com/

git remote add指令需要两个参数:

  • 远程仓库名,如origin
  • 远程仓库地址,如https://github.com/user/repo.git

通过以下指令查看远程仓库信息:

1
2
3
4
git remote -v
# Verify new remote
> origin https://github.com/YourName/Your-Projects-Name.git (fetch)
> origin https://github.com/YourName/Your-Projects-Name.git (push)

以下原因可能是 🪜 把 22 端口禁了

1
2
3
kex_exchange_identification: Connection closed by remote host
Connection closed by 198.18.0.63 port 22
fatal: Could not read from remote repository.

⚠️ 此时不能 push,如果远程仓库有本地仓库没有的文件,此时直接 push 会出错。

1
2
3
4
5
6
7
8
9
10
❯ git push -u origin main
Enter passphrase for key '/Users/chan/.ssh/id_ed25519':
To github.com:FacundoChan/Booking-System-Go.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:FacundoChan/Booking-System-Go.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

接着就是获取更新某个分支:

1
2
3
4
5
6
7
8
9
10
# 从远程仓库中获取某个分支的更新,再与本地指定的分支进行自动merge
git pull origin main

# 上述指令相当于执行了以下指令
git fetch origin main # 更新到本地仓库
git checkout main
git merge origin/main

# 或者合并
git pull --rebase origin main

查找仓库来源

有时候忘记自己是从哪个地方下载的仓库,这时候可以进入git clone的文件夹根目录,在该处打开终端并输入

1
2
git reflog --date=iso|grep clone
d94ea16 HEAD@{2022-08-15 11:54:24 +0800}: clone: from git://g.csail.mit.edu/6.824-golabs-2022

设置与查看配置

Git 的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)

1
2
3
4
# 显示当前的Git配置
git config --list
# 编辑Git配置文件
git config [--global] -e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 设置提交代码时的用户信息
git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"

# 字体配置
# Display UTF-8 characters in filenames, if you're having problems seeing them
git config --global core.quotepath false

# 颜色设置
git config --global color.ui true # git status等命令自动着色
git config --global color.status auto
git config --global color.diff auto
git config --global color.branch auto
git config --global color.interactive auto
git config --global --unset http.proxy # remove proxy configuration on git
git config --global core.editor "nvim" # git使用系统默认编辑器,在这里我改成nvim
git config --global core.editor "code --wait"
# 使用vscode打开,并等待关闭

git config --global diff.tool vscode # difftool名设为vscode
git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE" # 设置启动vscode ⚠️注意config是否正确写入!

查看配置

1
2
3
git config --system --list   # 查看系统配置
git config --global --list # 查看当前用户(global)配置
git config --local --list # 查看当前仓库配置信息

.gitignore

本地.gitignore文件通常被放置在项目的根目录中。 你还可以创建一个全局.gitignore文件,该文件中的所有条目都会在你所有的 Git 仓库中被忽略。

设置全局配置

创建全局.gitignore文件

1
vim ~/.gitignore

添加规则,如 mac 用户可忽略 macOS 自动创建的.DS_Store等。(更多

1
2
3
4
5
6
7
8
# General
.DS_Store

# Compiled Python files
*.pyc

# Compiled C++ files
*.out

也可以通过curl使用 GitHub 的默认 macOS 配置规则。

1
curl https://raw.githubusercontent.com/github/gitignore/master/Global/macOS.gitignore -o ~/.gitignore

也可以根据操作系统、项目语言、IDE 等为你的项目自动生成必要的.gitignore文件(gitignore.io

也可以在项目文件夹下可自定义规则,常用规则如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

使用

如何查询某一指令的帮助文档

1
git add -h  # 查看git add的帮助信息

文件管理

添加 track

1
2
git add .                 # 添加所有文件
git add ../apps/webget.cc # 添加指定文件

显示有关索引和工作树中文件的信息

1
git ls-files

删除文件

1
2
3
4
git rm -h # 查看帮助信息
# -r allow recursive removal
git rm -r --cached <file> # 不删除本地文件
git rm -r --f <file> # 删除本地文件

恢复文件

1
2
3
git restore <file>          # 在工作空间但是不在暂存区的文件撤销更改
git restore --staged <file> # 将暂存区的文件从暂存区撤出,但不会更改文件
git restore --source=HEAD~1 <file>

清理文件

1
2
3
4
5
6
7
8
9
10
# Print out the list of files and directories which will be removed (dry run)
git clean -n -d
# -n --dry-run: Don’t actually remove anything, just show what would be done.
# Specify -d to have it recurse into such directories as well

# Delete the files from the repository
git clean -f

git clean -fd # 删除当前目录下没有被track过的文件和文件夹
# 工作目录和缓存区将回到最近一次commit的状态
  • To remove directories, run git clean -f -d or git clean -fd
  • To remove ignored files, run git clean -f -X or git clean -fX
  • To remove ignored and non-ignored files, run git clean -f -x or git clean -fx

commit

1
2
3
4
git commit -m "commit content"
git commit # 调用文本编辑器输入(适合大量内容)

git commit --amend # 修改提交信息

commit 的一些 实用技巧 花里胡哨的东西

  • 通过emoji更直观地呈现

版本查看/对比

1
git difftool [--staged]
1
git diff origin/main # 查看本地版本库和远程版本库的区别
1
2
3
4
5
6
# 列出历史提交记录
git log [--oneline] [--reverse]
git show d601b90 # or d60
git show HEAD~2 # HEAD往前2个版本
git show 1dcc30
git show HEAD~1:bin/app.bin # 查看具体文件内容

分支管理

1
2
git checkout master  # 切换到master分支
git merge lab0-2 # 合并分支
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# push到远程仓库(如GitHub)
git push origin main
# 删除远程分支
git push origin --delete [branch name]
# 查看本地分支
git branch
# 查看远程分支
git branch -r
# 删除本地分支
git branch -D [branch name] # ⚠️是否已合并
# 本地分支重命名
git branch -m oldName newName

# compared with remote branch

git fetch
git diff remote/branch
# git fetch updates your tracking branches from the remote.
# git diff will compare the remote branch with your local branch.
删除远程分支

不小心在 GitHub 删除了分支,但本地 remote/origin/..还有的情况:

git remote prune origin will remove all such stale branches. That's probably what you'd want in most cases, but if you want to just remove that particular remote-tracking branch, you should do:

1
git branch -d -r origin/coolbranch

(The -r is easy to forget...)

-r in this case will "List or delete (if used with -d) the remote-tracking branches." according to the Git documentation found here: https://git-scm.com/docs/git-branch

查看信息

查看项目的当前状态,其中-s表示 short-format

1
git status [-s]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
X          Y     Meaning
-------------------------------------------------
[ AMD] not updated
M [ MTD] updated in index
T [ MTD] type changed in index
A [ MTD] added to index
D deleted from index
R [ MTD] renamed in index
C [ MTD] copied in index
[ MTARC] index and work tree matches
[ MTARC] M work tree changed since index
[ MTARC] T type changed in work tree since index
[ MTARC] D deleted in work tree
R renamed in work tree
C copied in work tree
-------------------------------------------------
D D unmerged, both deleted
A U unmerged, added by us
U D unmerged, deleted by them
U A unmerged, added by them
D U unmerged, deleted by us
A A unmerged, both added
U U unmerged, both modified
-------------------------------------------------
? ? untracked
! ! ignored
-------------------------------------------------

版本回滚

1
2
3
4
5
6
7
8
# 回滚到具体版本
git reset --hard commit_id

# 回退上个版本
git reset --hard HEAD^

# 回退上上个版本
git reset --hard HEAD^^

删除后续 commits 并更新 main 分支

1
2
3
4
5
git branch backup-main
git checkout backup-main
git reset --hard 594a5d1
git branch -D main
git branch -m backup-main main

版本回退并删除后续 commits 并更新 GitHub

错误 commit 并 push 到远程仓库之后的操作

1
2
3
4
5
6
7
8
git checkout main
git reset --hard 594a5d1
git push origin +main

root@cs144vm:/home/cs144/sponge/build# git push origin +main
Total 0 (delta 0), reused 0 (delta 0)
To github.com:FacundoChan/CS144.git
+ 594a5d1...b511bd6 main -> main (forced update)

Git 对象

  1. Commits
  2. Blobs (Files)
  3. Trees (Directories)
  4. Tags

Git Aliases

Add & Commit

Alias Add & Commit
gaa git add --all
gc git cimmit -v
Alias Work in Progress
gst git status

其他资料

MIT Version Control (Git) Git Book Git docs 常用指令 Git Aliases Git Tutorial for Beginners: Learn Git in 1 Hour

gitignore 规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#注释           .gitignore的注释
*.txt 忽略所有 .txt 后缀的文件
!src.a 忽略除 src.a 外的其他文件
/todo 仅忽略项目根目录下的 todo 文件,不包括 src/todo
build/ 忽略 build/目录下的所有文件,过滤整个build文件夹;
doc/*.txt 忽略doc目录下所有 .txt 后缀的文件,但不包括doc子目录的 .txt 的文件

bin/: 忽略当前路径下的 bin 文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
/bin: 忽略根目录下的 bin 文件
/*.c: 忽略 cat.c,不忽略 build/cat.c
debug/*.obj: 忽略debug/io.obj,不忽略 debug/common/io.obj和tools/debug/io.obj
**/foo: 忽略/foo, a/foo, a/b/foo等
a/**/b: 忽略a/b, a/x/b, a/x/y/b等
!/bin/run.sh 不忽略bin目录下的run.sh文件
*.log: 忽略所有 .log 文件
config.js: 忽略当前路径的 config.js 文件

/mtk/ 忽略整个文件夹
*.zip 忽略所有.zip文件
/mtk/do.c 忽略某个具体文件
1
2
3
4
5
6
7
8
9
10
11
12
13
cs144@cs144vm:~/sponge/build$ ssh -T git@github.com
git@github.com: Permission denied (publickey).
cs144@cs144vm:~/sponge/build$ ssh-add ~/.ssh/id_cs144.pub
Could not open a connection to your authentication agent.
cs144@cs144vm:~/sponge/build$ eval `ssh-agent -s` # run it first
Agent pid 3323
cs144@cs144vm:~/sponge/build$ ssh-add ~/.ssh/id_cs144.pub # then execute `ssh-add`
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/cs144/.ssh/id_cs144.pub' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
  1. Push to a valid branch: If you find that the branch name in the remote repository is different from what you expected, you will need to adjust your push command accordingly. For example, if the branch name is "main" in the remote repository, but your local branch is named "master," you can push to the remote "main" branch using:

    bash

    Copy

    1
    git push my6.824 master:main

Make sure to replace "master" with the correct local branch name if it's different in your case.

[^ 1]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes


Git 笔记 📒
http://example.com/2022/07/13/git-note/
作者
臣皮蛋
发布于
2022年7月13日
许可协议