Git基本命令与远程仓库使用


基本使用

设置用户名/邮箱

安装git后先设置,相当于本机器自报家门

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

查看git配置信息

1
git config --list

注意 git config 命令的 --global 参数,用了这个参数,表示你这台机器上所有的 Git 仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和 Email 地址。
也可以通过修改git配置文件,配置文件位置:用户-.gitconfig

提交步骤

把目录变成 Git 可以管理的仓库

1
git init

查看文件状态

1
git status

把文件提交到暂存区

1
git add 文件名

向仓库中提交代码

1
git commit

参数:

  • -m 本次提交的说明: 附带提交说明提交
  • -a: 同时保存暂存区(该操作对未添加到暂存区的文件无效)

提交文件原则:每一次提交只包含一个功能,不要在一次提交中包含多个功能

查看提交记录

1
git log

这是一个强大的日志输出命令,提供了众多可选选项,通过 git log --help 查看所有选项。

默认情况下,git log 按照默认输出格式,通过交互式滚动输出全部的提交日志,默认格式为:

1
2
3
4
5
commit 00e59eb74e217cbb70022b02b2b5a67afcde5a1e (origin/dev-3.2.2, dev-3.2.2)
Author: MarryDream <2190758465@qq.com>
Date: Fri Dec 15 20:41:54 2023 +0800

build: optimizing the way docker connects to host services

这其中 commit 后较长的 SHA-1 字符串为 commit id

我们可以通过自定义选项来修改默认的输出格式,常用格式化输出结果选项:

选项 说明
–format 使用给定格式输出提交日志内容,可选项有 onelineshortmediumreferenceemailrawformat:<string>
–abbrev-commit 仅显示 SHA-1 的前 6 个字符,而非全部的 40 个字符
–oneline –format=oneline –abbrev-commit 组合选项的简写
–date 使用给定的格式输出提交日志中的日期内容,可选项有 localrelativeformat:<string>
其中 format:<string> 后跟随 strftime 格式占位符,例如 --date=format:"%Y-%m-%d %H:%M:%S"
–relative-date 等同于 --date=relative,展示相对时间(例如 3 weeks ago

默认情况下,git log 不生成任何 diff 输出,下面是常用 diff 输出选项:

选项 说明
-p 按补丁格式显示每个更新之间的差异
–stat 直观展示每个文件的增删修改统计信息
例如: src/modules/plugin.ts | 5 +--
–shortstat 仅展示 --stat 的最后一行的文件改动信息 7 files changed, 64 insertions(+), 12 deletions(-)
–name-only 仅展示改动文件的列表
–name-status --name-only 的基础上新增改动文件的状态,例如: M .gitignore
–graph 在左侧追加提交线

一些可选选项可以对输出结果进行一层过滤:

选项 说明
-n -3 显示最近 3 条 commit 记录
–author 仅显示指定作者相关的提交
–committer 仅显示指定提交者相关的提交
–before 仅显示指定时间之前的提交
–after 仅显示指定时间之后的提交
–grep 仅显示含有指定关键字的提交

撤销操作

删除文件

删除文件并添加到暂存区

1
git rm /test/path/test-file.md

等效于下面两步

  1. 手动删除 /test/path/test-file.md
  2. git add /test/path/test-file.md

撤销暂存

旨在让 git 不再管理此文件

1
2
3
4
5
# 取消托管指定路径下的所有文件
git rm -r --cached <dir_path>

# 取消托管指定文件
git rm --cached <file_path>

撤销当前改动

即回退到最近一次提交,有如下几种操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 将整个项目回退到最近一次提交,非常激进的操作
git reset --hard

# 将指定路径下所有当前文件回退到最近一次提交,不包括被删除文件
git checkout <dir_path>

# 将指定文件回退到最近一次提交,要求文件必须存在,不支持被删除文件
git checkout <file_path>

# 将指定路径下所有文件回退到最近一次提交,包括被删除文件
git checkout HEAD -- <dir_path>

# 将指定文件回退到最近一次提交,支持被删除文件
git checkout HEAD -- <file_path>

版本回退

在 Git 中,用 HEAD 表示当前版本,上一个版本为 HEAD^,上上个版本为 HEAD^^,往上第 100 个版本为 HEAD~100

注:当执行版本回退操作时,会清空所有当前未提交未暂存的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 整体回退到最新版本(还原全部未提交改动)
git reset --hard

# 整体回退到上一个版本
git reset --hard HEAD^

# 返回指定版本
# 1094a 为 commit id, 输几位就可以
git reset --hard 1094a

# 查看每一次的命令
# 可以找到记录的commit id 来回退
git reflog

总结:HEAD 指向的版本就是当前版本,因此,Git 允许我们在版本的历史之间穿梭,使用命令 git reset --hard commit_id
穿梭前,用 git log 可以查看提交历史,以便确定要回退到哪个版本。要重返未来,用 git reflog 查看命令历史,以便确定要回到未来的哪个版本。

分支操作

Git鼓励大量使用分支

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查看分支
git branch

# 创建分支
# 在哪一个分支进行操作,就是基于哪一个分支创建分支,相当于基于哪一个分支创建副本
git branch <branch_name>

# 切换分支
# 未提交的改动将会一并被移动到新分支,若未提交的改动与新分支存在冲突,则阻止切换分支
git checkout <branch_name>

# 创建+切换分支
git checkout -b <branch_name>

# 安全删除分支
# 当分支未合并至当前分支时无法正常删除
git branch -d <branch_name>

# 强制删除分支
git branch -D <branch_name>

合并分支

将指定分支内容合并至当前分支,分为两种合并方式

若两个分支同时改动了一处地方,则会出现冲突,需要解决冲突

本文 gif 图来源: 🌳🚀 CS Visualized: Useful Git Commands - DEV Community

merge

1
git merge <branch_name>

这种合并方式将会创建一个新的 merge commit 节点来合并两个分支的改动

演示图

提交线的效果图如下

效果图

而当当前分支未作任何提交,仅目标分支存在改动时,将会移动目标分支的 commit 节点至当前分支,不会创建 merge commit 节点。

演示图

优点:保留提交线原始格式,易于溯源,非常安全绝对不会出错的合并方式
缺点:提交线杂乱难以阅读

rebase

1
git rebase <branch_name>

这种合并方式将会提升当前分支的 commit 节点,并将被合并分支的 commit 节点插入到当前分支 commit 节点之前

演示图

提交线的效果图如下

效果图

优点:不会出现新的 merge 节点,提交线整洁易于阅读,完全使用 rebase 合并分支的项目会只有一条提交线
缺点:打乱了提交线,不懂原理的新手随意操作会造成无法挽回的结果

解决冲突

在多人同时开发一个顶目时,如果两个人修改了同一个文件的同一个地方,就会发生冲突。根据拉取代码方式,分为两种情况

  • git pull: 解决冲突后,需要手动 commit 一个 merge 提交。若存在手动改动的部分,还需要在 commit 之前手动保存至暂存区
  • git rebase: 解决冲突后执行 git rebase --continue,继续处理其他后续可能存在的冲突。全部解决完毕后与 git pull 后续操作一致

合并某分支到当前分支

1
2
# 应当切换到合并分支上,来合并被合并分支(如要将dev合并到master分支,则应切换到master分支,进行合并操作)
git merge <name>

暂时保存更改

在 git 中,可以暂时将分支上所有的改动保存到临时存储区,让开发人员得到一个干净的工作副本,临时转向其他工作。

使用场景:分支临时切涣、存储临时改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 保存当前所有未提交的改动
git stash push
# git stash push 的别名
git stash

# 保存时添加一个描述性的信息,最终描述信息为 `On <branch_name>: <message>`
# 默认情况下描述信息为 `WIP on <branch_name>: <branch_id> <current_commit_message>`
git stash -m "<message>"

# 列出所有保存的 stash
git stash list

# 取出指定的 stash,并从 stash 列表中删除该 stash
git stash pop stash@{n}
# 等效于 git stash pop stash@{0}
git stash pop

# 取出指定的 stash,但不删除该 stash
git stash apply stash@{n}
# 等效于 git stash apply stash@{0}
git stash apply

stash 区域是独立于分支的,不管在哪个分支执行 popapply 都会将改动恢复到此分支,因此需要注意所在的是哪个分支

PowerShell 中 {} 被认作代码块执行标识符,需要对 {} 使用 ` 转义,写法为 git stash apply stash@`{n`}

更改已存在的提交信息

git commit 的 --amend 参数可以将当前工作目录中的修改添加到最新一次提交中,并可以修改最新的这次提交的相关信息

我们可以利用这个特性来直接修改最后一次提交的相关信息,例如修改最后一次提交的作者信息

1
2
# 不需要修改提交信息时,可以添加 --no-edit 跳过提交信息修改
git commit --amend --author="author <email>" --no-edit

修改多条已存在的提交信息

可以借助 rebase 依次编辑的特性,来实现对多条 commit 信息进行修改

例如修改最近 10 条 commit 的作者信息

1
2
3
4
git rebase -i HEAD~10
# 将 pick 修改为 edit,保存退出
git commit --amend --author="author <email>" --no-edit
git rebase --continue

同步提交时间与创建时间

每一个提交都存在创建时间提交时间两个时间,通常情况下这两个时间是相同的。
但在执行 --amendrebase 等修改分支的操作后,提交时间会和创建时间存在一定的差异

为了避免出现昨天的提交在今天的提交之后的诡异情况,我们需要将提交时间与创建时间均同步为当前时间。

首先我们需要获取当前的系统时间,根据不同命令行系统有各自不同的获取操作:

  • Command Prompt: echo %date% %time%
  • PowerShell: Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
  • Git Bash/Linux: date

之后可借助 --date 参数来对分支创建时间进行修改,在参数值中,可以使用 $() 执行系统命令

1
2
3
4
5
6
# Command Prompt
git commit --amend --no-edit --date "$(echo %date% %time%)"
# PowerShell
git commit --amend --no-edit --date "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
# Git Bash/Linux
git commit --amend --no-edit --date "$(date)"

最后可通过 [修改多条已存在的提交信息][#修改多条已存在的提交信息] 来批量修改分支的提交时间

远程仓库使用(以github为例)

创建仓库

  • 仓库名:不能和其他仓库名称重复
  • Description:描述信息,可选
  • README.md:对仓库的详细描述,给其他人看的

邀请合作者

setting-manage access
复制 invite link(邀请链接)发送给合作者

远程仓库别名相关

可以给远程仓库定义别名,来简化操作

1
2
3
4
5
6
7
8
9
10
11
# 查看别名列表
git remote -v

# 给远程仓库起别名
git remote add <alias> <repository_url>

# 修改别名
git remote rename <old_alias> <new_alias>

# 删除别名
git remote rm <alias>

向远程仓库推送本地仓库

首先记得先在当前仓库设置用户名和邮箱(优先级大于全局设置,该设置不会被推送至远程仓库)

1
2
git config user.name "Your Name"
git config user.email "email@example.com"

推送本地仓库的不同方式

1
2
3
4
5
6
7
8
# 正常推送
git push <origin_respository_url> <branch_name>

# 用别名推送
git push <origin_respository_alias> <branch_name>

# 记住推送地址及分支,下次推送只需要输入 git push 即可
git push -u <origin_respository_alias> <branch_name>

不同分支推送

默认情况下将本地内容推送至与本地同名的线上分支,可以修改这个默认行为

1
git push <origin_respository_alias> <local_branch_name>:<origin_branch_name>

查看远程仓库分支

1
2
3
4
5
# 查看指定别名的远程仓库信息
git remote show origin

# 也可以直接查看所有分支(包含本地与远程分支)
git branch -a

删除远程仓库分支

1
2
3
git push origin -d <origin_branch_name>
# 或是
git push origin :<origin_branch_name>

删除后再次执行 git remote show 查看远程状态时,会发现该分支依旧存在,并被添加了备注标记:

1
refs/remotes/origin/dev-3.0.1 stale (use 'git remote prune' to remove)

此时需要执行以下命令来同步本地与远程分支改动

1
git remote prune origin

拉取远程仓库内容

获取远程仓库内容的操作分为完整克隆拉取更新指定分支内容两种操作

克隆远程仓库

完整克隆下载远程仓库内容,这对本地来说是一个从无到有的过程。

使用此种方法下载的仓库文件包含完整的 .git 托管记录文件,这与直接点击 Download ZIP 下载源码压缩包有本质上的区别

1
2
3
4
5
6
7
8
# 克隆远程仓库到本地
git clone <origin_respository_url>

# 修改克隆后创建的目录名称(默认为仓库名称)
git clone <origin_respository_url> <new_folder_name>

# 指定克隆的目标分支(默认为仓库作者设定的主分支)
git clone -b <branch_name> <origin_respository_url>

拉取远程仓库内容

拉取更新远程仓库内容,这是建立在已经存在一个本地仓库的前提下进行的。

其拥有两种拉取方式 fetchpull 严格意义上讲,后者包含前者

fetch

fetch 会将远程分支内容拉取到本地,以 <origin_respository_alias>/<branch_name> 的命名方式定义为一个远程分支的本地副本(非本地分支)

可通过 git branch -a 来查看这些副本分支。

1
2
3
4
# 更新远程仓库的所有分支至本地副本
git fetch <origin_respository_alias>
# 更新远程仓库的指定分支至本地副本
git fetch <origin_respository_alias> <branch_name>

pull

pull 会拉取远程指定分支内容,并合并至本地分支,其合并方式有两种 mergerebase

1
2
3
4
# 默认 merge 方式合并
git pull <origin_respository_alias> <branch_name>
# rebase 方式合并
git pull -r <origin_respository_alias> <branch_name>

他其实是 fetchmerge / rebase 两个命令的组合操作

1
2
3
4
5
6
7
8
9
git pull origin dev
# 等效于
git fetch origin dev
git merge origin/dev

git pull -r origin dev
# 等效于
git fetch origin dev
git rebase origin/dev

既然 pull 的操作包含 merge / rebase,他也存在出现冲突的可能,在必要的情况下需要手动解决冲突

git pull 和 git clone 的区别

命令 区别
git pull 和本地版本进行对比,仅仅拉取最新版本,在已经有本地仓库的基础上进行
git clone 完全克隆远程仓库,在没有本地仓库的基础上进行

当本地仓库版本落后于远程仓库版本时,不能进行提交,需要先进行 git pull 拉取最新版本

跟踪仓库

设置后再次使用 push 与 pull 时,无需指定仓库地址与分支名称,直接 git pullgit push 即可

1
git branch --set-upstream-to=远程仓库别名/分支名称 本地分支名称

公钥和私钥

只有在远程仓库中存入了公钥,才能使用 ssh 提交。

ssh 相比 http 提交的好处:让远程仓库认识本机,免于 pullpush 时需要输入 github 用户密码
需要开发者用命令生成,实际就是两个文件,其中公钥要放在 github 账户中,私钥保留在开发者电脑中。

生成密钥

1
ssh-keygen -t ed25519 -C "your_email@example.com"

密钥默认存储目录

1
2
3
4
# windows
C:\User\用户\.ssh
# linux
~/.ssh

生成的密钥默认名:

  • 私钥(rsa:非对称加密方式): id_rsa
  • 公钥: id_rsa.pub

github 公钥存放地址

1
头像 - setting - SSH and GPG keys - New SSH key

即将生成的 id_rsa.pub 文件里面的内容复制进去
设置好后,推送时会对电脑中的私钥和github中的公钥配对,配对成功即成功推送