Git工作面试必知必会操作-命令行篇

本文已收录在Github关注我,紧跟本系列专栏文章,咱们下篇再续!

  • 🚀 魔都架构师 | 全网30W技术追随者
  • 🔧 大厂分布式系统/数据中台实战专家
  • 🏆 主导交易系统百万级流量调优 & 车联网平台架构
  • 🧠 AIGC应用开发先行者 | 区块链落地实践者
  • 🌍 以技术驱动创新,我们的征途是改变世界!
  • 👉 实战干货:编程严选网

0 下载安装及基本配置

安装成功后,打开,右击选择options进行个性化设置:

字体:

版本:

1 版本控制

1.0 简介

一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。开发中,我们仅对保存着软件源代码的文本文件作版本控制管理,但实际可对任何类型的文件进行版本控制。

采用版本控制系统,可将某个文件回溯到之前状态,甚至将整个项目都回退到过去某个时间点的状态。

可比较文件的变化细节,查出最后谁修改了啥地方,找出导致怪异问题出现的原因,又是谁在何时报告某功能缺陷等。

使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改的改删的删,你也照样可恢复如初,额外增加的工作量微乎其微!

1.1 本地版本控制系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单。不过坏处也不少:有时候会混淆所在的工作目录,一旦弄错文件丢了数据就没法撤销恢复。

为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异

最流行的一种叫做 rcs,现今许多计算机系统上都还看得到它的踪影。甚至在流行的 Mac OS X 系统上安装了开发者工具包之后,也可以使用 rcs 命令。它的工作原理基本上就是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录着对应文件修订前后的内容变化。所以,根据每次修订后的补丁,rcs 可以通过不断打补丁,计算出各个版本的文件内容,像WPS也有类似功能。

1.1 集中化的版本控制系统

如何让在不同系统上的开发者协同工作? 于是,集中化的版本控制系统( Centralized Version Control Systems,CVCS )应运而生。 诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法

每个人都可以在一定程度上看到项目中的其他人正在做些什么。 管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。

缺陷

中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。 最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端偶然提取出来的保存在本地的某些快照数据就成了恢复数据的希望。但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。 本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

于是分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世!

1.3 分布式版本控制系统

像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。

优势

任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份:

许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。

2 Git 发展史

Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds )不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统制订了若干目标:

  • 速度
  • 简单的设计
  • 对非线性开发模式的强力支持(允许上千个并行开发的分支)
  • 完全分布式
  • 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,它还有着令人难以置信的非线性分支管理系统(见第三章),可以应付各种复杂的项目开发需求。

3 Git 命令

3.1 Git配置

bash 复制代码
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

git config命令的--global参数,表明这台机器上的所有Git仓库都会使用这个配置,也可以对某个仓库指定不同的用户名和邮箱地址。

修改提交人

bash 复制代码
git commit --amend --author="JavaEdge <JavaEdge@gmail.com>"
# 再
git push -f

3.2 分区

3.2.1 工作区

PC里能看到的目录。实际的文件目录,包含项目文件。

工作区有一个隐藏目录.git,是Git的版本库。

3.2.2 版本库

包含完整的项目历史和分支信息。包括:

  • stage(或称index)暂存区。git add就是把文件从工作区添加到暂存区
  • Git自动创建的master(现已避嫌,改为main分支),默认的主分支,包含提交历史
  • 指向master的指针HEAD:指向当前分支的指针

git commit 把暂存区的所有内容提交到当前分支。

查看工作区状态

bash 复制代码
$ git status 
On branch feature/caict
Your branch is up to date with 'origin/feature/caict'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   src/main/java/com/javaedge/MqttClientConsumer.java

no changes added to commit (use "git add" and/or "git commit -a")

查看修改内容

bash 复制代码
# 可以查看工作区(work dict)和暂存区(stage)的区别
$ git diff
diff --git a/src/main/java/com/javaedge/MqttClientConsumer.java b/src/main/java/com/javaedge/MqttClientConsumer.java
index 9c65ba5..89bffdd 100644
--- a/src/main/java/com/javaedge/MqttClientConsumer.java
+++ b/src/main/java/com/javaedge/MqttClientConsumer.java
@@ -348,7 +348,7 @@ public class MqttClientConsumer {
             // 6. 关闭Producer
             producer.shutdown();
         } catch (Exception e) {
-            System.err.println("发送消息到RocketMQ异常: " + e.getMessage());
+            log.error("发送消息到RocketMQ异常: " + e.getMessage());^M
             e.printStackTrace();
         }
     }
bash 复制代码
# 查看暂存区(stage)和分支(master)的区别
$ git diff --cached
bash 复制代码
# 查看工作区和版本库里最新版区别
$ git diff HEAD -- <file>

保存工作现场

bash 复制代码
$ git stash

查看工作现场

bash 复制代码
$ git stash list

恢复工作现场

bash 复制代码
$ git stash pop

发现工作现场

bash 复制代码
$ git stash apply

3.3 仓库

初始化Git仓库

bash 复制代码
$ git init

添加文件到Git仓库

bash 复制代码
# 可反复多次使用,添加多个文件
$ git add <file>

# 可一次提交很多文件,-m后输入本次提交说明,可为任意内容
$ git commit -m "description"

3.4 日志

查看提交日志

bash 复制代码
$ git log
commit a3a04a5c5c1f8a03ab70f7e69af61c2fc014630b (HEAD -> feature/caict, origin/feature/caict)
Author: JavaEdge <javaedge@gmail.com>
Date:   Tue Jul 29 16:18:00 2025 +0800

    feat:新增 rocketmq 客户端依赖并发送测试topic消息,但发送失败

简化日志输出信息

bash 复制代码
$ git log --pretty=oneline
a3a04a5c5c1f8a03ab70f7e69af61c2fc014630b (HEAD -> feature/caict, origin/feature/caict) feat:新增 rocketmq 客户端依赖并发送测试topic 消息,但发送失败

查看命令历史

bash 复制代码
$ git reflog
a3a04a5 (HEAD -> feature/caict, origin/feature/caict) HEAD@{0}: commit: feat:新增 rocketmq 客户端依赖并发送测试topic 消息
,但发送失败
ab64e5d HEAD@{1}: commit: perf:消息基本转换完毕

3.5 回退

版本回退

bash 复制代码
$ git reset --hard HEAD^

返回到上一版本。

  • HEAD 当前版本
  • HEAD^ 上一版本
  • HEAD^^ 上上个版本
  • HEAD~n n 个版本之前

回退到指定版本

bash 复制代码
$ git reset --hard commit_id

commit_id是版本号,SHA1计算出的序列值。

调整commit之间的顺序

先看当前提交历史:

bash 复制代码
$ git log --oneline
208dff8 (HEAD -> feature/caict, origin/feature/caict) perf:发消息成功
a3a04a5 feat:新增 rocketmq 客户端依赖并发送测试topic 消息,但发送失败
ab64e5d perf:map消息基本转换完毕

将add N提交挪到c2提交之前:

css 复制代码
$ git rebase -i b0aa963

b0aa963用来确定commit范围,表示从此提交开始到当前的提交(不包括b0aa963提交)。

运行此命令后,弹出VIM编辑器:

bash 复制代码
# commit提交排列顺序与git log排列相反,最先提交的在最上面

# pick表示保留此次commit提交不做修改
pick e773755 C2
4f66467 C3
pick 7703131 add 1
O4643d add 2
pick f0cc6b6 add 3

# Rebase b0aa963..f0cc6b6 onto b0aa963 (5 commands)

# Commands:  底部给出所有可用的命令
# p, pick = use commit, but edit the commit message
# r, reword = use commit, but stop for amending
# e, edit = use commit, but stop for editing
# s, squash = use commit, but meld into previous commit
# f, fixup = Like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

手动调整一下对应提交的位置:

java 复制代码
pick 7703136 add 1
O4643d add 2
pick f0cc6b6 add 3
pick e773755 C2
4f66467 C3

保存离开就可以自动完成,再看提交历史记录:

java 复制代码
git log --oneline (HEAD -> master)
6c59aa9 c3
cd09550 add 3
68a5550 add 2
f5c53c0 add 1
471cafa c1

调整影响:无论调整commit顺序或删除commit,都有可能产生冲突或者错误。如后面的提交对前面的有依赖性,而删除前面的提交,势必出问题。好比穿越时空来到父母恋爱之时,这时候如果热恋中的父母分手,那自己又会从哪来?

提交

bash 复制代码
git cherry-pick

3.6 撤销

丢弃工作区的修改

bash 复制代码
$ git checkout -- <file>

将文件在工作区的修改全部撤销,两种case:

  • file自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
  • file已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态

总之,就是让这文件回到最近一次git commit或git add时的状态。

丢弃暂存区的修改

分两步: 第一步,把暂存区的修改撤销掉(unstage),重新放回工作区:

bash 复制代码
$ git reset HEAD <file>

第二步,撤销工作区的修改

bash 复制代码
$ git checkout -- <file>

小结:

  1. 当你改乱工作区某文件内容,想直接丢弃工作区的修改,用git checkout -- <file>

  2. 不但改乱工作区某文件内容,还添加到了暂存区,想丢弃修改,分两步:

    1. git reset HEAD <file>,就回到了第一步

    2. 第二步按第一步操作

  3. 已提交不合适的修改到版本库,想撤销本次提交,就进行版本回退,但前提是没推送到远程库

3.7 删除

删除文件

bash 复制代码
$ git rm <file>

git rm <file>相当于执行

bash 复制代码
$ rm <file>
$ git add <file>

Q:rm text.txt 误删,咋恢复? A:git checkout -- text.txt ,把版本库的东西重新写回工作区

Q:执行git rm text.txt,发现工作区的text.txt也删除了,咋恢复? A:先撤销暂存区修改,重新放回工作区,然后再从版本库写回到工作区

bash 复制代码
$ git reset head text.txt
$ git checkout -- text.txt

Q:真想从版本库里删除文件咋做? A:执行git commit -m "delete text.txt",提交后最新的版本库将不包含这个文件

git rm V.S git rm --cached

需删除暂存区或分支上的文件,同时工作区也不需要该文件了:

bash 复制代码
git rm file_path 

需删除暂存区或分支上的文件,但本地又需要使用,只是不希望该文件被版本控制:

bash 复制代码
git rm --cached file_path

3.8 远程仓库

创建SSH Key

bash 复制代码
$ ssh-keygen -t rsa -C "xxx@gmail.com"
bash 复制代码
~ % cat  /Users/javaedge/.ssh/id_rsa.pub

贴到github的ssh key即可开启ssh免密访问。

关联远程仓库

bash 复制代码
$ git remote add origin https://github.com/username/repositoryname.git

【取消】关联远程仓库

取消 Git 仓库与远程仓库的关联:

bash 复制代码
git remote remove https://github.com/Java-Edge/education-microservice.git

不确定远程仓库名称,就查看远程仓库列表:

bash 复制代码
javaedge@JavaEdgedeMac-mini education-microservice % git remote -v
origin  https://github.com/Java-Edge/education-microservice.git (fetch)
origin  https://github.com/Java-Edge/education-microservice.git (push)

列出所有与你的本地仓库相关联的远程仓库及其 URL。再按需用第一个命令取消关联特定的远程仓库。

推送到远程仓库

bash 复制代码
$ git push -u origin master

-u 表示第一次推送master分支的所有内容,此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改。

bash 复制代码
fatal: The upstream branch of your current branch does not match
the name of your current branch.  To push to the upstream branch
on the remote, use

    git push origin HEAD:release/10.0

To push to the branch of the same name on the remote, use

    git push origin HEAD

与本地建立联系的是远程的 release 分支,因此git 报错会提示应该这么把代码推到远程的特定分支

bash 复制代码
git push origin  HEAD:release/10.0

从远程克隆

为了得到一个项目的备份,需知该项目仓库地址(Git URL)。Git能在许多协议下使用,所以Git URL可能以ssh://、http(s)://、git://或只是以一个用户名(git 会认为这是一个ssh 地址)为前辍。有些仓库可通过不只一种协议访问。如Git本身源码可用:

git:// 协议访问:

bash 复制代码
git clone git://git.kernel.org/pub/scm/git/git.git

也可通过http 协议来访问:

java 复制代码
git clone http://www.kernel.org/pub/scm/git/git.git

git://协议较为快速和有效,但有时须用http协议,如你公司防火墙阻止非http访问请求。若执行上面两行命令中的任一,你会看到一个新目录: 'git',包含有所的Git源代码和历史记录。

Git会把"Git URL"里最后一级目录名的'.git'的后辍去掉,做为新克隆(clone)项目的目录名,如:

java 复制代码
git clone http://git.kernel.org/linux/kernel/git/torvalds/linux-2.6.git

会建立一个目录叫'linux-2.6'。

若访问一个Git URL需用户名、密码,可在Git URL前加上用户名,并在它们之间加上@符合以表示分割,再执行git clone,git提示你输入密码。

示例

bash 复制代码
git clone javaedge@http://www.kernel.org/pub/scm/git/git.git

将以作为 javaedge 用户名访问:

java 复制代码
http://www.kernel.org/pub/scm/git/git.git

然后按回车键执行git clone命令,git会提示你输入密码。

可通过-b <name>指定要克隆的分支名:

bash 复制代码
$ git clone -b master2 ../server .

表示克隆名为master2的这个分支,如果省略-b 表示克隆master分支。

bash 复制代码
$ git clone https://github.com/usern/repositoryname.git

删除远程仓库文件

可能某些不需要的目录上传到远程仓库去了,下面开始操作

预览将要删除的文件

bash 复制代码
# 加上 -n 参数,执行命令时,不会删除任何文件,而是展示此命令要删除的文件列表预览
git rm -r -n --cached 文件/文件夹名称 

确认后删除

bash 复制代码
git rm -r --cached 文件/文件夹名称

提交到本地

bash 复制代码
git commit -m "提交说明"

并推送到远程服务器

bash 复制代码
git push origin master

3.9 分支

创建分支

bash 复制代码
$ git branch <branchname>

查看分支

bash 复制代码
# 列出所有分支,当前分支前面会标一个*号。
$ git branch
* feature/caict
  main
  master

查看远程分支

bash 复制代码
$ git branch -a
* feature/caict
  main
  master
  remotes/origin/HEAD -> origin/main
  remotes/origin/feature/caict
  remotes/origin/main
  remotes/origin/master

查看本地分支和远程分支之间的映射关系:

bash 复制代码
$ git branch -vv
* feature/caict 208dff8 [origin/feature/caict] perf:发消息成功
  main          95f1bb6 [origin/main: ahead 1, behind 1] Initial commit
  master        95f1bb6 [origin/master] Initial commit

切换分支

bash 复制代码
$ git checkout <branchname>
bash 复制代码
# 切换远程分支
git checkout -b release/10.0  origin/release/10.0 

创建+切换分支

bash 复制代码
$ git checkout -b <branchname>

合并某分支到当前分支

bash 复制代码
$ git merge <branchname>

删除分支

bash 复制代码
$ git branch -d <branchname>

查看分支合并图

bash 复制代码
$ git log --graph

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。用git log --graph命令可以看到分支合并图。

普通模式合并分支

bash 复制代码
$ git merge --no-ff -m "description" <branchname>

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。合并分支时,加上--no-ff参数就可以用普通模式合并,能看出来曾经做过合并,包含作者和时间戳等信息,而fast forward合并就看不出来曾经做过合并。

丢弃一个没有合并过的分支

bash 复制代码
$ git branch -D <branchname>

查看远程库信息

bash 复制代码
$ git remote -v

在本地创建和远程分支对应的分支

bash 复制代码
$ git checkout -b branch-name origin/branch-name,

本地和远程分支的名称最好一致;

建立本地分支和远程分支的关联

bash 复制代码
$ git branch --set-upstream branch-name origin/branch-name;

从本地推送分支 (将本地项目与远程仓库项目关联)

bash 复制代码
$ git push origin branch-name
java 复制代码
sssdeMacBook-Pro:ArticleSpider sss$ git push -u origin master
Counting objects: 18, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (18/18), 4.32 KiB | 2.16 MiB/s, done.
Total 18 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/Wasabi1234/Scrapy-Tutorial.git
   1c84622..bc4cf9a  master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

如果推送失败,先用git pull抓取远程的新提交;

从远程抓取分支

bash 复制代码
$ git pull

如果有冲突,要先处理冲突。

3.10 标签

tag让人容易记住的有意义的名字,跟某commit绑在一起。

新建一个标签

bash 复制代码
$ git tag <tagname>

默认为HEAD,也可指定一个commit id。

指定标签信息

bash 复制代码
$ git tag -a <tagname> -m <description> <branchname> or commit_id

git tag -a <tagname> -m "blablabla..."可以指定标签信息。

PGP签名标签

bash 复制代码
$ git tag -s <tagname> -m <description> <branchname> or commit_id

git tag -s <tagname> -m "blablabla..."可以用PGP签名标签。

查看所有标签

bash 复制代码
$ git tag

推送一个本地标签

bash 复制代码
$ git push origin <tagname>

推送全部未推送过的本地标签

bash 复制代码
$ git push origin --tags

删除一个本地标签

bash 复制代码
$ git tag -d <tagname>

删除一个远程标签

bash 复制代码
$ git push origin :refs/tags/<tagname>

参考:

本文由博客一文多发平台 OpenWrite 发布!

相关推荐
老白干16 分钟前
jjwt 0.9.1 在 JDK 11+ 上的两个“坑”与完整解决方案
java·python·log4j
笨鸟先飞,勤能补拙7 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能8 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂8 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study8 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境9 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境9 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1239 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021610 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb0010 小时前
一个项目带你入门AI应用开发01
python