Git&GitHub Desktop常用操作入门

给小白的版本控制教程

Posted by Miso on February 8, 2026

0. 前言 我们为什么需要Git


对于大型软件开发而言,版本管理的重要程度是不言而喻的。Git为我们提供了极为重要的两大功能——历史跟踪,以及协作合并。

历史跟踪可以让我们清楚地看到每一个版本之间的演变,知道某个新版本是由哪一个老版本演化而来。

协作合并可以让多位工作者在不同分支同时修改某一份代码,最后尝试将他们的修改整合起来。

作为当下最流行的版本控制工具,Git在程序界的地位和方向盘在驾驶界的地位差不多。

掌握Git,然后,在代码里拥抱新生。

1. 软件 工具与准备


使用图形界面操作Git

Git有两种使用方式,分别是命令行和图形界面。新手建议使用图形界面进行Git操作,不必记忆繁琐的指令。

推荐使用GitHub Desktop进行图形界面Git操作。下载GitHub Desktop将内置一个特定版本的Git,无需手动部署Git。

本文将基于GitHub Desktop进行Git操作讲解。以GitHub作为远程代码托管平台。

图为GitHub Desktop主界面。

登录GitHub

请在GitHub Desktop内登录你的GitHub账号。

设置你的名字和邮箱

Git依赖名字和邮箱跟踪每一次修改是何人所做。请前往File-Options-Git来设定名字和邮箱。

第零个Git操作-新建仓库

仓库是Git的重要概念。它就是一个文件夹,文件夹内的一切便是Git的管辖范围。仓库文件夹和工程所用的文件夹是相同的,也就是说,这个文件夹里的最外层应当装着main.py这种文件。

通过File-New Repository来创建新仓库。填写名称、描述,选择本地路径。

1
2
3
4
----本地跟踪器----
【无】
----云端跟踪器----
【无】

这便是仓库建立后的样子。

2. 单分支基本操作


基本概念快速上手

我们可以把几乎一切Git行为表述为:把代码在几个地方之间抛来抛去。这几个地方分别是:

代码编辑器窗口

硬盘

Git本地跟踪器

Git云端-GitHub

从代码编辑器到硬盘的操作是“保存-Save”,按一下Ctrl+S好了。

从硬盘到Git本地跟踪器的操作是 “提交-Commit”

从Git本地跟踪器到云端的操作是 “推送-Push”

从云端把别人的代码弄到本地的操作是 “拉取-Pull”

下面将重点讲述这三个概念。

提交

“提交”可以认为是“保存”这一操作的进阶版本。当我们触发“提交”操作时,Git会自动确定上一次提交并构建联系、生成文件的哈希值、记录提交者的信息,最终把提交记录固定在本地跟踪器中。每一次提交都有一个唯一的“上次提交(父提交),表示这次提交是从哪一次提交修改而来。

当你进行了代码修改并进行保存之后,GitHub Desktop会在左栏显示“xx changed files”,此时左下角的提交-Commit按钮会亮起。请在按钮上方的文本框里描述这次修改的内容供人知晓,按下左下角的提交-Commit按钮,你的修改将被提交到本地跟踪器。

1
2
3
4
5
6
7
8
----本地跟踪器----    ----云端跟踪器----
|                           【无】
* 3 添加新函数
|
* 2 添加Hello World
|
* 1 初始化仓库

请看,三次Commit形成了一条提交的链子,一个接着一个。

推送

“推送”是将本地跟踪器的提交上传至云端的过程。当你的本地跟踪器跟踪了云端跟踪器没有跟踪上的提交(如上图,1 2 3三次提交都还没有上传至云端),GitHub Desktop上侧黑栏最右侧的按钮将会变成Push字样,伴有向上箭头。

按下Push的瞬间,本地跟踪器的数据将上传至云端。

1
2
3
4
5
6
7
8
----本地跟踪器----    ----云端跟踪器----
|                     |    
* 3 添加新函数        * 3 添加新函数
|                     |
* 2 添加Hello World   * 2 添加Hello World
|                     |
* 1 初始化仓库        * 1 初始化仓库

拉取

拉取发生在我们希望得到别人推送到云端的代码时。

1
2
3
4
5
6
7
8
9
10
----本地跟踪器----    ----云端跟踪器----
                      |
                      * 4 加入新模式 *Csugu
|                     |    
* 3 添加新函数        * 3 添加新函数
|                     |
* 2 添加Hello World   * 2 添加Hello World
|                     |
* 1 初始化仓库        * 1 初始化仓库

此时Csugu添加了一个新的提交并推送至云端,而我希望将这段最新的代码拉取至本地。此时GitHub Desktop上侧黑栏最右侧的按钮将会变成Pull字样,伴有向下箭头。

按下Pull,云端跟踪器的代码数据将同步到本地。

1
2
3
4
5
6
7
8
9
10
----本地跟踪器----    ----云端跟踪器----
|                     |
* 4 加入新模式 *Csugu * 4 加入新模式 *Csugu
|                     |    
* 3 添加新函数        * 3 添加新函数
|                     |
* 2 添加Hello World   * 2 添加Hello World
|                     |
* 1 初始化仓库        * 1 初始化仓库

3. 多分支基本操作


什么是分支?我们为什么需要多分支?

当我们按下Ctrl+Z撤回操作的时候,必然是逆着操作,4 3 2 1一步步撤回的。

Git也是如此。我们需要在跟踪器里删除提交节点时,也需要4 3 2 1一步步倒退着撤回。

我现在发现:* 3 添加新函数这一次提交出现问题,需要撤回。此时我若尝试撤回,就会发现:无论如何,Csugu的* 4提交都必须先撤回,尽管他的改动与我在* 3里修改的函数完全无关。

也就是说,Csugu必然会丢代码。

为了解决这一问题,我们不妨规定同一个分支上绝不能同时混合着提交两种以上的功能开发。这样,只有一种功能改动时,撤回Git的操作不至于影响到其它功能的开发。

那,如果我们需要同时开发多种功能,我们应该怎么办?此时我们需要多分支开发。

新建分支&签出分支&提交到分支

让我们回到两种功能还没混合到一起的时候。

1
2
3
4
5
6
----本地跟踪器----    ----云端跟踪器----
|                     |
* 2 添加Hello World   * 2 添加Hello World
|                     |
* 1 初始化仓库        * 1 初始化仓库

此时,我将添加新函数,Csugu将加入新模式。我们将各自在此新建一个分支。

在GitHub Desktop中点击Branch-New branch,输入分支名,便可新建分支。

1
2
3
4
5
6
7
8
----本地跟踪器----                    ----云端跟踪器----
| |
| |-> * Miso 新分支:新建函数 
|/                                    |
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

签出分支后,GitHub Desktop上侧黑栏“Current branch”处将显示当前分支名。任何仓库都有一个默认的分支,称为main(旧称master),意为主分支。刚才未新建分支时进行的两次提交1和2便是在主分支上。

本文的示意图中永远在最左侧使用铅垂线的|领起主分支,用/符号在右侧领起其它分支

GitHub Desktop新建分支后默认切换到此分支。也可以通过点击Current branch来方便地切换分支。

任何提交都会提交到Current branch。现在让我进行这次提交。

1
2
3
4
5
6
7
8
9
10
----本地跟踪器---- @ Miso             ----云端跟踪器----
| |
| * 3 添加新函数
| |
| |-> * Miso 新分支:新建函数 
|/                                    |
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

可以看到,提交已发送至“新建函数”分支。

看看Csugu那边战况如何:

1
2
3
4
5
6
7
8
9
10
----本地跟踪器---- @ Csugu            ----云端跟踪器----
| |
| * 4 加入新模式
| |
| |-> * Csugu 新分支:新模式 
|/                                    |
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

我们在各自的分支上均完成了开发。现在,让我们把各自的分支上传到云端。

推送分支到云端

在GitHub Desktop中,当你签出到一个尚未与云端建立联系的本地分支(例如“新建函数”或“新模式”)时,上侧黑栏最右侧的按钮会显示“Publish branch”,并伴有云朵和向上箭头的图标。

按下“Publish branch”,GitHub Desktop会执行两个操作:

  1. 在云端(GitHub)创建一个同名的新分支。
  2. 将当前本地分支的所有提交(例如提交* 3)推送到这个新创建的云端分支。

让我们看看Miso按下发布按钮后,云端的变化:

1
2
3
4
5
6
7
8
9
----本地跟踪器---- @ Miso             ----云端跟踪器----
| |                                   | |
| * 3 添加新函数                      | * 3 添加新函数
| |                                   | |
| |-> * Miso 新分支:新建函数         | |-> * origin/新建函数
|/                                    |/
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

可以看到,云端跟踪器里多出了一个名为 origin/新建函数 的分支(origin/ 前缀表示这是远程分支),并且包含了提交 *3。

同样地,Csugu也发布他的“新模式”分支:

1
2
3
4
5
6
7
8
9
----本地跟踪器---- @ Csugu            ----云端跟踪器----
| |                                   | |              |
| * 4 加入新模式                      | * 4 加入新模式 * 3 添加新函数
| |                                   | |              |
| |-> * Csugu 新分支:新模式          | |-> * 新模式   |-> * 新建函数
|/                                    |/              /
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

此时,云端共出现三个分支:main、新模式、新建函数。

分支发布后的常规推送

一旦分支发布成功,本地分支就和云端分支建立了跟踪关系。此后,你在这个分支上产生新的提交,上侧黑栏的按钮会变回熟悉的“Push origin”。

就像在主分支上操作一样,点击它即可将新的提交推送到对应的云端分支。

查看云端分支

发布后,你可以在GitHub网站上的仓库页面,通过分支下拉菜单看到这两个新分支。团队成员现在都能看到这些分支,并可以基于它们进行代码审查、测试或后续的合并操作。

在本地进行分支合并

现在,我和Csugu已经在各自的分支上完成了开发。下一步便是把这两个分支的改动合并回主分支。

请将Current branch切换回主分支main,点击Branch-Merge into current branch,选择我的开发分支。

结果如下图

1
2
3
4
5
6
7
8
9
----本地跟踪器---- @ Miso             ----云端跟踪器----
 |                                    | |              |
 |                                    | * 4 加入新模式 * 3 添加新函数
 |                                    | |              |
 * 3 添加新函数                       | |-> * 新模式   |-> * 新建函数
/                                     |/              /
* 2 添加Hello World                   * 2 添加Hello World
|                                     |
* 1 初始化仓库                        * 1 初始化仓库

此时Git触发了快进合并机制,这是Git合并操作的两种常用手法之一。因为主分支从分支分叉之后没有更新,主分支选择直接将指针侵入开发分支并指向开发分支顶端,两个分支重叠在一起。这一过程中分支之间没有“合并”的操作,因此常常使新手感到困惑。

分支仍然存在于本地。因为分支的所有修改已经被主分支承载,分支本身已没有意义。新的开发可以启用新的分支,因而你可以选择删除旧分支。主分支和”添加新函数“分支已经完全重叠——图中不再将这一分支画出。

Push一次,将这次改动上传至云端。

1
2
3
4
5
6
7
8
9
----云端跟踪器----
|                |
* 3 添加新函数   * 4 加入新模式 
|                |
|                |-> * 新建函数
|               /
* 2 添加Hello World
|
* 1 初始化仓库

Csugu此时通过Pull操作将这次改动同步到自己的本地跟踪器上。

1
2
3
4
5
6
7
8
9
----本地跟踪器---- @ Csugu
|                |
* 3 添加新函数   * 4 加入新模式 
|                |
|                |-> * 新建函数
|               /
* 2 添加Hello World
|
* 1 初始化仓库

切换回主分支,同样进行merge操作。此时,由于主分支上已经有一个节点* 3,主分支的顶端指针不能直接进入开发分支。Git将启用传统合并流程。

1
2
3
4
5
6
7
8
9
10
11
12
----本地跟踪器---- @ Csugu
|
* 5 Merge from branch "新建函数"
|                \
|                |
* 3 添加新函数   * 4 加入新模式 
|                |
|                |-> * 新建函数
|               /
* 2 添加Hello World
|
* 1 初始化仓库

一个全新的提交节点* 5从主分支上建立起来,Git将同时参考* 2 * 3 * 4三个提交的信息共同创建* 5。一般来说,只要* 3和* 4不是修改了* 2的同一行,* 5就能顺利生成。

Push一次,将这次改动发送回云端。我可以通过Pull进行同步。

4. 在云端进行分支合并-Pull Request-拉取请求


除了在本地进行合并,GitHub还提供了一个更强大、更规范的协作工具:拉取请求 (Pull Request,简称PR)。

我们为什么需要拉取请求?

本地合并的流程是这样的:

  1. Miso先合并:我切换到主分支,将“新建函数”分支合并进来(触发了快进合并)。然后我需要手动推送到云端。
  2. Csugu后合并:Csugu需要先拉取我刚刚推送到云端的主分支更新,然后才能尝试将自己的“新模式”分支合并到主分支。由于此时主分支已经有了我的新提交(3),Git触发了传统合并,生成了一个合并提交(5)。最后Csugu再推送这个合并结果。
  3. 我再次同步:我需要再次拉取Csugu合并后的主分支,才能获得最终完整的代码。

因为每次合并都是在某人的本地进行的,这套流程里渗透着大量的推送到云端-拉取回本地的操作,非常麻烦。

同时,我和Csugu真的有权利在不经审查的情况下把代码直接合并到主分支吗?

什么是拉取请求?

拉取请求是一个提议,它向仓库的维护者(或团队成员)发出信号:“我已完成了一个功能的开发,请审查我的代码,并将其合并到主分支。”若团队审查通过,将会在云端进行分支合并。

这是一个代码审查、讨论和最终合并的标准化流程,是团队协作中保证代码质量的关键环节。

创建拉取请求

  1. 前往GitHub网站:打开你的仓库页面。
  2. 切换到你的分支:在分支下拉菜单中,选择你刚刚发布的功能分支(例如 新建函数)。
  3. 点击“Compare & pull request”按钮:GitHub会检测到你的分支领先于主分支,并显示此按钮。
  4. 填写PR信息:
    • 标题:清晰描述这个PR的目的,例如“添加用户登录功能”。
    • 描述:详细说明你做了哪些修改,为什么这么做,以及测试情况等。这有助于审查者理解你的代码。
    • 审查者:可以指定团队成员来审查你的代码。
    • 标签:可以添加如 enhancement(功能增强)、bug-fix(错误修复)等标签进行分类。
  5. 创建PR:点击“Create pull request”按钮。至此,一个PR就创建好了,它会出现在仓库的“Pull requests”标签页中。

代码审查与讨论

其他团队成员(或被指定的审查者)可以在PR页面中:

  • 查看所有更改:逐行浏览你修改的代码。
  • 发表评论:对某行代码提出疑问或建议。
  • 进行讨论:在PR的对话区进行更广泛的讨论。

这是一个学习和提高代码质量的好机会。根据反馈,你可以在本地分支上继续修改、提交并推送,这些新的提交会自动更新到这个PR中。

合并拉取请求

当所有讨论结束,代码审查通过后,仓库的维护者(或有合并权限的人)就可以执行合并操作。

在PR页面的底部,点击绿色的 “Merge pull request” 按钮。GitHub提供了几种合并方式(通常选择默认的“Create a merge commit”即可),点击确认后,你的分支就会被合并到主分支(main)中。

合并完成后:

  1. 云端的主分支将包含你分支上的所有提交。
  2. PR的状态会变为“已合并”。
  3. 你可以选择删除已经完成使命的云端功能分支(GitHub会提示你这样做)。

本地同步

最后,别忘了回到你的GitHub Desktop:

  1. 签出到主分支 (main)。
  2. 点击 “Pull origin” 按钮,将云端刚刚合并好的最新主分支代码拉取到本地。

5. 关于那些零散的概念


git add&reset

将多个文件的修改分拆至多次提交——这两个概念已经被现代Git图形化界面中的”文件打勾“功能所容纳。可在GitHub Desktop左侧的文件栏中进行勾选,以确定这次提交所提交的文件。

git stash

这一操作是在切换分支时,将还没提交的修改暂存起来。GitHub Desktop会在切换分支时询问:”将未提交的修改暂存起来,还是带去你要前往的分支?“,选择前者即触发git stash。回到分支时,可从左侧文件栏重新取出暂存的修改。

git reset

用于删除已有的提交来撤回提交。DeepSeek这么说:

  1. git reset –soft:最温和。它只移动HEAD指针(和当前分支指针)到指定的提交,但保留暂存区和工作目录的修改。这相当于“撤销了提交,但保留了所有修改并准备重新提交”。适合修改提交信息或合并多个提交。
  2. git reset –mixed (默认):常用模式。移动HEAD指针,并且重置暂存区到指定提交的状态,但保留工作目录的修改。这相当于“撤销了提交,并且把修改从暂存区里拿了出来”。适合撤销一次错误的提交,然后重新选择部分文件提交。
  3. git reset –hard :最危险。移动HEAD指针,并且同时重置暂存区和工作目录,完全回到指定提交的状态。所有未提交的修改都将被永久丢弃。请谨慎使用!

简化一下就是

  1. git reset –soft:删除提交,在文件栏中使提交涉及的文件全部打勾
  2. git reset –mixed (默认):删除提交,在文件栏中使提交涉及的文件全部不打勾
  3. git reset –hard :删除提交,同时删除涉及文件的修改,使其在文件栏中消失。

在GitHub Desktop中,你可以在历史记录中右键点击某个提交,选择“Undo commit”或“Revert changes in commit”,这些操作背后就是不同模式的 reset。它提供了更安全的图形化操作,避免了命令行误操作的风险。

git revert

这一操作将创建一个”撤销的提交“,用来撤销commit。在GitHub Desktop中,你可以在历史记录中右键点击一个已推送的提交,选择“Revert commit”。GitHub Desktop会自动创建一个新的“还原提交”并暂存,你只需要填写提交信息并推送即可。这是撤销已公开错误的首选方法。

6. 结语


Git对于我来说,可能是重要程度仅仅次于IDE的工具。无数个夜晚我、Csugu和Tecrel在不同的分支上开发着IFAWL,完全不担心自己的推送和撤回对别人造成影响。我们在GitHub上为要紧的提交打上版本号的tags,看着Git的提交树不顾一切地向上生长,那时的我们感觉仿佛能把全世界掌握在手中。

它是迈入开发世界的最基本的技能,也是最易学难精的技能。分支、推进、合并,让心弦随着提交线一同震颤,我觉得,这就是业余软件开发最让人欲罢不能的时刻。