Git使用详解

一、核心概念与原理

Git是Linus Torvalds 2005年为管理Linux内核开发而创造的分布式版本控制系统,核心优势是本地高速操作、完整仓库副本、轻量分支、SHA-1 哈希防篡改,现已成为全球代码协作的标准工具

1、四大区域(工作区/暂存区/本地仓库/远程仓库)

在这里插入图片描述
在这里插入图片描述

1. 工作区(Working Directory): 电脑上的项目文件夹,日常编辑、新增、删除文件都在这里,改动后未被Git记录
2. 暂存区(Staging Area/Index): .git/index 文件,临时存放待提交的文件列表信息,用于选择性提交,让每次提交逻辑清晰
3. 本地仓库(Local Repository): git目录,存储所有提交的历史快照、分支、标签等,通过SHA-1 哈希唯一标识每个提交,防篡改
4. 远程仓库(Remote Repository): 托管在服务器(如 GitHub/Gitee)的仓库,用于团队协作与代码共享

2.、快照机制

Git 每次提交(commit)都是对当前所有文件做完整快照,未修改的文件只保留引用(不重复存储),因此检出速度极快、分支操作轻量

二、安装和初始化配置

1、安装

Windows:官网下载安装包,默认配置即可。
Linux(Ubuntu/Debian):sudo apt install git

2、初始配置(全局,仅一次)

# 设置用户名(必须,提交时显示)
git config --global user.name "你的名字"
# 设置邮箱(必须,与远程仓库账号一致)
git config --global user.email "你的邮箱@example.com"
# 查看配置
git config --list

# 创建秘钥
cat ~/.ssh/id_rsa.pub 或者 cat ~/.ssh/id_ed25519.pub
ssh-keygen -t ed25519/rsa -C "您的email"
clip < ~/.ssh/id_ed25519.pub
clip < ~/.ssh/id_rsa.pub

在这里插入图片描述

# Git全局设置:
git config --global user.name "张康聪"
git config --global user.email "1173410230@qq.com"
# 创建 git 仓库:
mkdir python-base-syntax
cd python-base-syntax
git init 
git remote add origin https://gitee.com/zkcJava/python-base-syntax_1.git
git remote add remote https://gitee.com/zkcJava/python-base-syntax.git
touch README.md
git status
git add README.md
git commit -m "first commit"

"""
1、创建仓库时勾选了初始化README、许可证、gitignore这些文件只在远程有,本地没有,Git检测到不一致,不让你直接推送
2、当别人最新提交的和你推送的有冲突时,需要先git pull
"""
# 1、第一次创建仓库
git pull origin master --rebase  # 第一次创建项目和仓库时要先执行,再进行推送
git push -u origin "master" # 直接执行可能会拒绝
# 2、当有冲突时
git pull origin master_20250525 --rebase # 将分支上新的修改拉取合并后,再进行推送
# 后续操作commit之后,只需要git push即可

# 已有仓库?
cd existing_git_repo
git remote add origin https://gitee.com/zkcJava/python-base-syntax.git
git push -u origin "master"

三、基础命令

1、仓库创建与克隆

# 1. 初始化本地仓库
创建一个空目录,通过git init命令把这个目录变成Git可以管理的仓库,当前目录下会多一个.git的目录,是Git用来跟踪管理版本库的,不要轻易改动,否则将会破坏Git仓库,该目录默认是隐藏的
git init

# 2. 克隆远程仓库到本地(自动关联远程)
git clone https://gitee.com/xxx/xxx-repo.git
# -b 指定分支
git clone –b master_20260525 https://gitee.com/xxx/xxx-repo.git

2、文件状态与暂存

文件状态:未跟踪(Untracked)→已修改(Modified)→已暂存(Staged)→已提交(Committed)

# 查看状态
git status: 用来查看当前工作区和暂存区的状态
* -s: 简洁模式
* 改完代码,先确认改了哪些文件
* commit之前,检查有没有漏add 

# 查看修改内容
用来比较文件差异,查看修改前后有什么变化
git diff: 看未暂存改动
git diff --staged: 看已暂存改动
git diff main..dev: 比较两个分支差异
git diff HEAD -- 文件名: 查看文件工作区和版本库里最新版本的区别
git diff HEAD -- .\README.md
diff --git a/README.md b/README.md
index 049df08..8ffa645 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,4 @@
 add 1
 add 2
 add 3
+add4
\ No newline at end of file

# 添加到暂存区
git add 用来把工作区的改动加入暂存区,只有先add,改动才会进入下一次commit
* 把修改过的文件放进暂存区
* 把新文件纳入git管理
* 选择本次要提交哪些改动
* 不会直接生成版本记录
* 只是暂存,不等于已经提交
* 使用git reset撤回暂存

git add 文件名.md        # 将单个文件添加到暂存区
git add .               # 添加当前目录所有变更(新增/修改/删除)
git add src/            # 添加整个目录
git add *.py            # 所有.py 文件
git add -p              # 交互式添加(选择性暂存部分修改)

3、提交到本地仓库

# 提交暂存区内容
git commit会把暂存区里的改动保存为一次提交,形成一个可追溯的版本快照
* -m: 本次提交的说明,可输入任意内容,最好是有意义的,这样你就能从历史记录里找到改动记录
* 只会提交已经add的内容
* 生成一条本地提交记录
* 生成唯一的commit ID
* 保存本次提交说明
* 把暂存区内容固定成一个版本
git commit -m "feat: 新增用户登录功能"

# 跳过暂存,直接提交所有修改(慎用)
git commit -a -m "fix: 修复登录密码加密bug"

# 为什么Git添加文件需要add,commit一共两步呢?
因为commit可以一次提git add file1.txt
git add file1.txt
git add file2.txt file3.txt
git commit -m "add 3 files."

4、查看历史

# 查看完整提交历史(含哈希、作者、时间、备注)
git log
# 简洁模式(一行显示一条提交)
git log --pretty=oneline

# 图形化查看分支关系
* --all:显示所有分支的提交
* --oneline: 一行显示一个提交(短ID+信息)  == --pretty=oneline --abbrev-commit
* --graph:**图形(ASCII 字符)** 展示分支、合并关系,能清晰看到谁从哪个分支分出来、谁合并了谁。
* --pretty=oneline: 格式化输出,每个提交只占一行,只显示:commit ID+提交说明
* --abbrev-commit:40位commit ID,缩写成7* --decorate: 显示分支名、标签名
"""
--oneline 等价于 --pretty=oneline --abbrev-commit
"""
# 漂亮的完整图形树
git log --graph --oneline
git log --graph --oneline --all
git log --graph --oneline --all --decorate
git log --graph --pretty=oneline --abbrev-commit


# 查看单文件的所有提交历史
git log --graph --oneline 文件名

# 查看详细提交内容
git log -p

# 只看最近N条记录
git log -5 --oneline

# 只看某个作者的提交
git log --author="张三"

# 搜索提交说明
git log --grep="修复登录bug"

# 查看单个文件的修改历史
git log 文件名.md

# 查看某次提交的详细修改
git show 提交哈希(前7位即可)

# 查看历史记录的版本号id
git reflog

5、远程仓库关联与同步

# 查看远程仓库(默认origin)
git remote -v

# 关联远程仓库(本地已存在仓库时用)
git remote add remote ssh://XXX.git
git remote add origin ssh://XXX.git

# 远程仓库地址变更
git remote set-url origin 远程仓库新URL

# 推送本地分支到远程(首次推送需-u关联)
git push 用来把本地仓库中的提交同步到远程仓库
* 上传本地的commit记录
* 更新远程分支
* 没有commit时,push不会上传代码改动
* 多人协作时,必要时先pull再push

"""
由于第一次远程库是空的,推送master分支时,加上了–u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来
1、当初始只有master分支时,本地master---origin master 进行绑定
第一次git push :git push -u origin master
后续commit:git push  等价于 git push origin master
2、当创建新分支master_20260525时,要先把新创建的分支推送到个人远程仓,下面有说明
因为不是创建仓库后的第一次git push,所以不加-u参数
后续commit:git push 等价于 git push origin master_20260525
"""
git push -u origin feature/login
* origin: 远程仓库名
* master、feature/login: 要推送的分支名

git push origin master
git push origin master_20260525
# 后续操作可直接推送 git push

# 创建新分支切换后,如果直接git push失败,则要把新创建的分支推送到个人远程仓,再进行推送
1. git config --global push.autoSetupRemote true # 以后所有新分支直接git push就能自动绑定远程,不用再加参数
2. git push --set-upstream origin master_20260523

# 拉取远程最新代码(合并到本地当前分支)
git pull 用来获取远程仓库的最新提交,并把他们合并到当前本地分支
* 拉取远程最新代码
* 更新当前本地分支
* 自动执行fetch+merge
git pull origin master
"""
1、创建仓库时勾选了初始化README、许可证、gitignore这些文件只在远程有,本地没有,Git检测到不一致,第一次往origin仓库master分支推送时不让直接推送,需要先git pull
2、当别人最新提交的和你推送的有冲突时,需要先git pull
"""
# 1、第一次创建仓库
git pull origin master --rebase  # 第一次创建项目和仓库时要先执行,再进行推送
git push -u origin "master" # 直接执行可能会拒绝
# 2、有冲突时
git pull origin master_20250525 --rebase # 将分支上新的修改拉取合并后,再进行推送
# 后续只需要git push即可

6、撤销修改与版本回退

回退到上个版本:HEAD^
回退到上上个版本: HEAD^^
回退到前100个版本:HEAD~100

$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file
# 1. 撤销工作区修改(未暂存)
git checkout -- 文件名
当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时:
git checkout -- readme.txt

# 2. 撤销暂存(保留工作区修改)
git reset HEAD 文件名
当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改时:
1. git reset HEAD 文件名
2. git checkout -- 文件名

# 3. 回退到指定提交(本地仓库,保留修改)
git reset --soft 提交哈希  # 回退commit,修改回到暂存区,回退到上个版本的未提交状态
git reset --mixed 提交哈希 # 默认,修改回到工作区,回退到上个版本已添加但未提交的状态
git reset --hard 提交哈希  # 回退到上个版本的已提交状态

# 4. 撤销远程提交(需强制推送,团队协作慎用)
git revert 提交哈希  # 撤销指定提交,生成新提交
git revert HEAD  # 撤销最近一次提交
# 版本回退
# 版本1:wrote a readme file
Git is a version control system.
Git is free software.
# 版本2:add distributed
Git is a distributed version control system.
Git is free software.
# 版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.

# 1. 使用git log查看历史记录
git log命令显示从"最近到最远"的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file
"1094adb...的是commit id(版本号),是一个SHA1计算出来的十六进制表示的数字"
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file

# 2. 确定当前版本
Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb...,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100^比较容易数不过来,所以写成HEAD~100

# 3. 把当前版本append GPL回退到上一个版本add distributed
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed

# 4. 查看readme.md,已经被还原
$ cat readme.txt
Git is a distributed version control system.
Git is free software.

# 5. git log 看看现在版本库的状态,最新的那个版本append GPL已经看不到了
$ git log --pretty=oneline
e475afc93c209a690c39c13a46716e8fa000c366 (HEAD -> master) add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file

# 6. 如果想再回到append GPL版本
只要上面的命令行窗口还没有被关掉,找到那个append GPL的commit id是1094adb...
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL

# 7. 查看readme.md,又回到append GPL版本
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL:
┌────┐
│HEAD│
└────┘
   │
   └──▶ ○ append GPL
        │
        ○ add distributed
        │
        ○ wrote a readme file
改为指向add distributed:
┌────┐
│HEAD│
└────┘
   │
   │    ○ append GPL
   │    │
   └──▶ ○ add distributed
        │
        ○ wrote a readme file
然后顺便把工作区的文件更新了

# 7. 如果回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file

在这里插入图片描述

7、文件删除操作

新建一个test.txt文件到Git并提交,如果直接在文件管理器中删除了该文件,或者使用rm/del命令删除,此时删除的是工作区的文件。
Git知道你删除了文件,因此,工作区和版本库就不一致了,可通过git status查看哪些文件被删除了。
在这里插入图片描述
1、第一种:确定要从版本库中删除该文件
此时版本库中还存在该文件,则使用git rm命令删除,并且通过git commit提交,再推送到个人远程库,再发起合并请求到公共远程仓进行合入
在pycharm中或者使用rm命令手动删除了文件,这是在工作区操作的,没有把这个修改放到暂存区,然后再使用“git rm”命令,就是把工作区删除文件的操作放到了暂存区
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b26980600e4941198e2f726743acd5d3.png
但如果直接用“git rm”命令,就相当于直接完成了“rm”和“git rm”这两个命令,前一个命令被自动执行了。这时候你再“git status”一下,你就会发现,你已经把删除工作区文件这个操作放到了暂存区,只等你提交到版本库里去了。

注意看git status的代码“ (use “git add/rm …” to update what will be committed)”。当你“rm”操作以后,再进行“git rm”,其实和“git add”的作用是等同的。

2、确定为误删文件
如果在工作区中误删除了文件,版本库仍然存在该文件,所以可以使用git checkout版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

git checkout -- test.txt

四、分支管理

分支是指向提交的轻量指针,创建 / 切换 / 合并几乎瞬间完成,支持并行开发、隔离功能、修复 bug

*:代表一个提交
|:表示不同分支的轨迹。
|/ :两个分支在此合并

1、分支基础命令

# 查看本地分支,带"*"表示当前分支
git branch  

# 创建分支(不切换)
git branch 分支名

# 切换分支
get checkout 最常见的用途是切换分支,也可恢复文件到指定状态
* -b: 创建并切换到新分支
* -- file.txt: 恢复文件
git checkout 分支名: 切换到某个分支
git switch 分支名: 切换到某个分支

# 创建并切换分支(常用)
# 等价于: 
git checkout -b 分支名  # 等价git branch 分支+git checkout 分支
git switch -c 分支名
git checkout -b 分支名 remote/master: 基于remote/master分支创建并切换分支


# 删除本地分支(已合并)
git branch -d 分支名
# 强制删除(未合并)
git branch -D 分支名

# 查看远程分支
git branch -r

2、分支合并(Merge)

将一个分支的代码合并到当前分支,保留提交历史,适合功能完成后合并到主分支

# 1. 切换到目标分支(如: master)
git checkout master

# 2. 合并分支
get merge: 用来把某个分支的提交合并到当前分支
git merge master_20260525: 把master_20260525分支合并到当前master分支
git merge feature/login: 把feature/login合并到当前master分支

在这里插入图片描述

2.1、解决冲突(合并时文件修改冲突)

# 1、同步公共远程库到本地
$ git fetch remote
$ git pull remote master --rebase
# 2、创建并切换到新分支
$ git switch -c feature1
Switched to a new branch 'feature1'
# 查看分支
$ git branch
* feature1
  master
  master_20260525
# 3、修改readme最后一行,改为
Creating a new branch is quick AND simple.
# 4、在feature1分支上提交
$ git add .\README.md
$ git commit -m "AND simple"
[feature1 3f518a3] AND simple
 1 file changed, 2 insertions(+), 1 deletion(-)
# 5、切换到master分支
$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 7 commits.
  (use "git push" to publish your local commits) # Git会自动提示我们当前master分支比远程的master分支要超前7个提交
# 6、在master分支上把readme.txt文件的最后一行改为:
Creating a new branch is quick & simple.
# 7、在master分支上提交
$ git add .\README.md
$ git commit -m "& simple"
[master 9756c6d] & simple
 1 file changed, 2 insertions(+), 1 deletion(-)

现在,master分支和feature1分支各自都分别有新的提交,变成了这样:
                            HEAD
                              │
                              ▼
                           master
                              │
                              ▼
                            ┌───┐
                         ┌─▶│   │
┌───┐    ┌───┐    ┌───┐  │  └───┘
│   │───▶│   │───▶│   │──┤
└───┘    └───┘    └───┘  │  ┌───┐
                         └─▶│   │
                            └───┘
                              ▲
                              │
                          feature1

这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突:
# 8、进行合并
$ $ git merge feature1
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

Git告诉我们,README.md文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件。
打开冲突文件,手动修改 <<<<<<< HEAD 与 >>>>>>> 之间的内容
解决后添加到暂存区并提交

# 9、再次提交
$ git add .\README.md
$ git commit -m "conflict fixed"
[master 7ffbd1f] conflict fixed

现在,master分支和feature1分支变成了下图所示:

                                     HEAD
                                       │
                                       ▼
                                    master
                                       │
                                       ▼
                            ┌───┐    ┌───┐
                         ┌─▶│   │───▶│   │
┌───┐    ┌───┐    ┌───┐  │  └───┘    └───┘
│   │───▶│   │───▶│   │──┤             ▲
└───┘    └───┘    └───┘  │  ┌───┐      │
                         └─▶│   │──────┘
                            └───┘
                              ▲
                              │
                          feature1

# 用带参数的git log也可以看到分支的合并情况
$ git log --graph --pretty=oneline --abbrev-commit
*   7ffbd1f (HEAD -> master) conflict fixed
|\
| * 3f518a3 (feature1) AND simple
| *   0b00fea (remote/master, remote/HEAD, master_20260525) merge master_20260525 into master
| |\
| * \   c86f3d0 merge master_20260525 into master
| |\ \
| * \ \   0a681cd merge master_20260525 into master
| |\ \ \
| * \ \ \   dd06afb merge master_20260525 into master
| |\ \ \ \
| * \ \ \ \   591b04d merge master_20260525 into master
| |\ \ \ \ \  
| * \ \ \ \ \   32a9d2f merge master_20260525 into master
| |\ \ \ \ \ \  
* | | | | | | | 9756c6d & simple
| |_|_|_|_|_|/  
|/| | | | | |
* | | | | | | 4de1ec7 (origin/master_20260525) readme forth commit
| |_|_|_|_|/
|/| | | | |
* | | | | | c9e93c3 readme third commit
| |_|_|_|/

# 删除feature1分支
$ git branch -d feature1
Deleted branch feature1 (was 3f518a3).
# 切换到 master_20260525
$ git switch master_20260525
Switched to branch 'master_20260525'
Your branch is ahead of 'origin/master_20260525' by 6 commits.
  (use "git push" to publish your local commits)
# 这步不一定做,前面修改了master的README.md文件,此时master_20260525分支上没有做修改,看情况要不要同步过来
$ git merge master
Updating 0b00fea..7ffbd1f
Fast-forward
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
# 上一步做了的话,要进行推送到远程库
$ git push        

3、变基(Rebase,高级合并)

git rebase用来将当前分支的提交变基到目标分支最新提交之上,提交历史线性整洁,适合个人分支同步主分支

与merge的不同:
rebase会改写提交的哈希值(产生新的提交),而merge会保留分支分叉并增加一个合并提交

绝对不要在公共分支执行 rebase + 强推,因为其他人可能基于这些提交工作。一旦你改了历史,别人的本地分支会变得混乱。只在自己的私有分支上做 rebase

# 变基到master分支
git rebase master: 把当前分支变基到master分支最新位置

# 解决冲突(同Merge,解决冲突后继续变基)
git add .
git rebase --continue

# 终止变基,回退原状
git rebase --abort

# 跳过当前冲突提交
git rebase --skip

# 交互式变基,可修改、合并、删除提交
git rebase -i <commitID>  # 变基到指定历史提交节点
git rebase -i HEAD~n(n=提交数)# 合并最近n个提交

# 推送变基后的分支(首次需 --force)
git push --force origin dev
git push -f origin dev

3.1、基础场景:将br_20260525分支变基到master分支

# 1. 初始状态
两个分支各自向前推进:
      A---B---C  br_20260525
     /
D---E---F---G    master
master:E → F → G
br_20260525(从E分出来):E → A → B → C

# 2. 执行Rebase
git checkout br_20260525
git rebase master
* 找到br_20260525与master的共同祖先(即E)
* 计算br_20260525相对于E的差异(提交A, B, C)
* 以master的最新提交G为新的基底,依次把 A, B, C 应用上去(可能需要解决冲突)

# 3. 结果状态
                A'---B'---C'  br_20260525
               /
D---E---F---G                 master
旧的 A, B, C 变成“悬空”对象(最终会被垃圾回收)
新的 A', B', C' 内容与原来相同,但 commit hash 不同,提交时间也会更新

# 3. git log 前后对比
变基前(在br_20260525分支上)
$ git log --oneline --graph --all
* c3a1b2c (br_20260525) C
* b2c3d4e B
* a1b2c3d A
| * f4e5d6c (master) G
| * e5d6c7b F
|/
* d4e5f6a E

变基后(在br_20260525分支上)
$ git log --oneline --graph --all
* x9y8z7w (br_20260525) C'
* y8z7w6v B'
* z7w6v5u A'
| * f4e5d6c (master) G
| * e5d6c7b F
|/
* d4e5f6a E
(注意:A',B',C' 的哈希值与原来完全不同)

3.2、交互式变基

  • -i: 交互式整理最近几次提交
假设我们有这样4个本地提交:
* 4444444 (feature) 添加调试日志
* 3333333 修复拼写错误
* 2222222 完成功能 A
* 1111111 初始实现
* 0000000 (main) 基础代码
想把它们整理成2个逻辑清晰的提交:合并前两个,并修改第三个的说明。

# 1. 执行交互式变基
git rebase -i HEAD~4   # 或 git rebase -i 0000000
# 2. 弹出编辑文件
pick 1111111 初始实现
pick 2222222 完成功能 A
pick 3333333 修复拼写错误
pick 4444444 添加调试日志
"""
字段说明:
pick:保留该提交,按原顺序应用
s/squash:合并到上一条提交(最常用)
edit:修改该提交的代码/备注
drop:直接删除该提交
"""
# 3. 修改文件,保存退出
pick 1111111 初始实现
squash 2222222 完成功能 A      # 将 2222222 合并到 1111111
reword 3333333 修复拼写错误    # 修改提交信息
drop 4444444 添加调试日志      # 删除该提交

# 4. Git会依次执行
合并1111111+2222222 → 新提交(合并后的信息可编辑)
重新生成3333333 的提交信息
跳过4444444

# 5. 得到干净的线性历史:
* 5555555 (feature) 修复拼写错误
* 6666666 初始实现 + 完成功能 A
* 0000000 (main) 基础代码

3.3、指定基点变基(rebase 到某个历史节点)

# 语法:
git rebase <基点commitID>
# 作用:
把当前分支,变基到任意一个历史提交节点,而非整个分支。

# 1. 原始状态
A --- B --- C --- D (main)
           \
             E --- F (dev)
# 2. 把dev变基到 提交B
先通过git log 拿到B的短commitID(假设为b123456)
git checkout dev
git rebase b123456
# 3. 变基后拓扑
A --- B --- C --- D (main)
       \
         E' --- F' (dev)
dev 直接嫁接在 B 节点之后,跳过了C/D

3.4、案例

# 1. 创建实验仓库
mkdir rebase-demo && cd rebase-demo
git init
echo "init" > file.txt; git add .; git commit -m "E"

# 2. 创建 feature 分支并做 3 个提交
git checkout -b feature
echo "A" >> file.txt; git commit -am "A"
echo "B" >> file.txt; git commit -am "B"
echo "C" >> file.txt; git commit -am "C"

# 3. 切回 main 并做 2 个提交
git checkout master 
echo "F" >> file.txt; git commit -am "F"
echo "G" >> file.txt; git commit -am "G"

# 4. 查看当前图形
git log --oneline --graph --all
* 17bf65b (HEAD -> master) G
* 1d9328e F
| * 9f61a65 (feature) C
| * 74cb5f5 B
| * 8c586f0 A
|/
* bf998d1 E

# 5. 执行 rebase
git checkout feature
git rebase master # 如果没有冲突,顺利完成
"""
冲突:
1. 打开file文件
init
<<<<<<< HEAD
F
G
=======
A
>>>>>>> 8c586f0 (A)

2. 编辑file.txt,删除冲突标记,保留正确顺序
init
F
G
A

3. 保存文件
git add file.txt
4. 解决冲突后继续rebase
git rebase --continue 执行后出现下面内容,:WQ保存退出即可
------------------------------------------------------------------------------
A
# Conflicts:
#       file.txt
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto f4c320c
# Last command done (1 command done):
#    pick c291597 # A
# Next commands to do (2 remaining commands):
#    pick 84b4e7d # B
#    pick 74b3f5b # C
# You are currently rebasing branch 'feature' on 'f4c320c'.
#
# Changes to be committed:
#       modified:   file.txt
---------------------------------------------------------------------------
"""
# 6. 再次查看图形(线性)
git log --oneline --graph --all
* fbb8362 (HEAD -> feature) C
* 2c98f97 B
* eb55ca3 A
* 17bf65b (master) G
* 1d9328e F
* bf998d1 E

4、分支管理策略

通常合并分支时,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

实战一下–no-ff方式的git merge:

1. 创建并切换dev分支:
$ git switch -c dev
Switched to a new branch 'dev'

2. 修改readme.txt文件,并提交一个新的commit
$ git add readme.txt 
$ git commit -m "add merge"
[dev f52c633] add merge
 1 file changed, 1 insertion(+)

3. 切换回master
$ git switch master
Switched to branch 'master'

4. 合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 1 +
 1 file changed, 1 insertion(+)
因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去

5. 合并后,我们用git log看看分支历史
$ git log --graph --pretty=oneline --abbrev-commit
*   e1e9c68 (HEAD -> master) merge with no-ff
|\  
| * f52c633 (dev) add merge
|/  
*   cf810e4 conflict fixed
...
可以看到,不使用Fast forward模式,merge后就像这样:

                                 HEAD
                                  │
                                  ▼
                                master
                                  │
                                  ▼
                                ┌───┐
                         ┌─────▶│   │
┌───┐    ┌───┐    ┌───┐  │      └───┘
│   │───▶│   │───▶│   │──┤        ▲
└───┘    └───┘    └───┘  │  ┌───┐ │
                         └─▶│   │─┘
                            └───┘
                              ▲
                              │
                             dev

五、双仓库工作流

Git Feature Branch Workflow(功能分支工作流)

5.1、基本步骤

# 关联两个远程仓
git remote add remote ssh://git@python-workspace.git  # 公共远程仓
git remote add origin ssh://git@python-workspace-1.git  # 个人远程仓

# 切到本地master
"""
1、不一定先切换到本地master分支,但按要求是要先切到本地master,再进行拉取和创建分支
前景: 
fetch+pull rebase两步已把当前分支变基到了remote/master之上,此时当前分支的内容已经包含了最新公共代码+你的旧修改
三种情况:
第一种:如果在此基础上继续开发新功能,可直接基于当前分支创建新分支,但本地master会不是最新的
第二种:如果是个人开发者,可直接基于当前分支创建新分支,但本地master会不是最新的
第三种:团队开发,强烈建议先切到本地master,再进行拉取和创建分支
"""
1. git checkout master

2. git fetch remote
"只是看看远程有没有更新,不碰本地代码"
git fetch用于从公共远程仓(remote)获取最新的提交历史和分支信息(最新代码)并下载到本地,但不会自动合并或修改当前本地代码

4. git pull remote master --rebase
把公共远程仓的master分支最新代码,用rebase平滑合并的方式"合并到你当前本地分支"
 
5. git checkout -b 新分支
从最新master创建新分支并切换,"或 从当前最新的分支创建新分支",保证代码是基于最新版开发

"""
1、每做新需求之前,先做上面四步,在新建的分支上写代码,每个需求一个新的分支
2、如果一个需求还没做完,可以在原先的分支上编写代码,不一定要做上面四步
"""

5. 开发→暂存→提交
git add .
git commit -m "修复xx问题"

6. 推送到个人仓库(origin)
git push origin 20260522_master

7. 下次要修改时,再次循环第一步

在这里插入图片描述

5.2、常见问题

1、git fetch remote 和 git pull remote master --rebase 是什么意思?

git fetch remote 用于从公共远程仓获取最新的提交历史和分支信息(最新代码)并下载到本地。但不会自动合并或修改本地任何分支的工作区
只是让本地知道远程仓库的最新状态(比如remote/master这个指针更新到了哪个提交)

fetch: 只下载数据,本地代码不变,纯查询同步
当执行 git fetch命令时,它会执行以下操作:
* 检查远程仓库是否有新的提交或分支
* 获取远程仓库的最新提交历史,但不会应用到当前工作目录中
* 更新本地仓库的远程分支指针,指向远程仓库的最新提交
大多数情况是单仓库(只有一个origin),如果是双仓库(公共remote+个人origin),fetch是必备第一步

git pull remote master --rebase
把公共远程仓的master分支最新代码,用rebase的方式"合并到你当前本地分支"
等价于:1)git fetch remote master: 获取远程master分支的最新提交
(2)git rebase remote/master: 将当前分支上的本地提交变基到remote/master之上

2、在创建分支之前有没有必要做fetch+pull rebase?

# 必要的情形:
想在最新公共代码的基础上创建新分支进行开发执行这两步可以确保本地拥有最新的remote/master,并且当前所在的分支会变基到最新代码上。
这样创建新分支时,基于一个已同步了最新公共代码的分支会减少将来合并时的冲突。

#不必要的情形:
如果不关心基础是否最新,或者完全独立于公共代码开发,可以跳过。但通常团队协作中,每天开始工作前同步一下公共代码是良好习惯。

#关键点:
这两步并不是创建分支的硬性要求,但为了保持与公共仓库的同步,避免后期大量冲突,"推荐在创建新功能分支前执行"

3、在commit且push之后不做fetch+pull rebase,可不可以直接创建分支?

可以,但非常不推荐。
随时可以创建新分支,这个新分支会基于你当前所在的提交(HEAD指向的位置)创建。
如果你当前在br_20250525上,并且已经commit并push到了个人仓库origin,但还没有同步公共仓库remote的最新代码,那么br_20250525可能落后于公共master。直接基于它创建新分支,会让新分支也继承这个“落后”的状态。

后果:
后续当需要把新分支的代码合并回公共master时,可能需要处理很多因为基础代码不同步而产生的冲突。所以"虽然技术上可以,但不推荐"

4、当前分支是br_20250525,执行完前面两步后会同步到本地master分支还是当前分支?

: 会同步到当前分支br_20250525

git fetch remote: 下载remote/master的最新指针,存储在本地远程跟踪分支remote/master中,不影响任何本地分支
git pull remote master --rebase: 若当前在br_20250525,会将br_20250525上独有的提交变基到remote/master的最新提交之上

最终:
br_20250525的内容更新为: "最新公共master+你的本地提交"
本地master分支完全不受影响(除非你之前已经切换到 master)

所以操作后,你的br_20250525变基到了公共最新代码上,而本地的master分支可能依然停留在旧的提交。

5、每次创建分支是基于本地master还是当前分支?是不是必须要切换到本地 master后再创建分支?

"默认基于当前分支(HEAD 指向的位置)"
git checkout -b new-branch 会"基于当前所在分支"的最新提交创建新分支
如果基于本地master创建新分支,就需要先切换到本地master,然后执行创建命令:
git checkout master
git checkout -b br_20250526
如果你想基于某个远程分支(比如 remote/master)创建,可以:
git checkout -b br_20250526 remote/master
这样不需要先切换到master

是否需要先切换到本地master?
不一定。可以直接从任何分支创建新分支,但为了清晰,习惯在创建新功能分支前,先切换到本地master并确保它是最新的(通过git pull remote master 或 git fetch remote; git reset --hard remote/master),然后再切出新分支。这样可以保证新分支完全基于公共最新代码。

两步操作实际上已经把当前分支变基到了remote/master之上,那么此时br_20250525的内容就已经包含了最新公共代码+你的旧修改。如果想在此基础上继续开发新功能,可以直接基于它创建新分支,效果等同于“基于最新公共代码加上一些旧提交”。

6、“pull into ‘br_20260525’ using rebase” 相当于 git pull remote master --rebase?

在IDE中,可能会有“pull into current branch using rebase” 的选项,并让你选择远程分支(如 remote/master)。
其实际执行的命令就是:
git pull --rebase remote master等价于git pull remote master --rebase(–rebase 放在前后均可)

六、刷新远程仓库列表

在 PyCharm 中,点击菜单栏的 “VCS”,选择 “Git”,再点击 “Fetch”,此操作会从远程仓库获取最新信息,可能会刷新出你添加的 “master” 仓库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一位不知名民工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值