MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Node.js版本控制Git常用命令总结

2023-08-227.4k 阅读

初始化版本库

在开始使用 Git 进行项目版本控制时,首先要做的就是初始化一个 Git 版本库。这一步会在指定的目录下创建一个隐藏的 .git 目录,该目录包含了所有版本控制相关的数据和配置。

命令

git init

示例: 假设我们有一个名为 nodejs_project 的 Node.js 项目目录,进入该目录后执行 git init 命令。

cd nodejs_project
git init

执行后,会在 nodejs_project 目录下生成一个 .git 目录。这个目录结构非常重要,它包含了对象数据库(存储项目的各个版本数据)、引用(如分支、标签等)以及配置文件等。虽然初始化后项目还没有任何提交记录,但已经具备了使用 Git 进行版本控制的基础。

克隆远程版本库

当项目已经在远程代码托管平台(如 GitHub、GitLab 等)上有了版本库,我们可以通过克隆的方式将远程项目完整地下载到本地。

命令

git clone <远程版本库地址>

示例: 假设在 GitHub 上有一个 Node.js 项目的远程版本库地址为 https://github.com/username/nodejs_demo.git,要将其克隆到本地,执行以下命令:

git clone https://github.com/username/nodejs_demo.git

执行此命令后,Git 会在当前目录下创建一个名为 nodejs_demo 的目录,并将远程版本库中的所有文件和版本历史下载到该目录中。这里涉及到 Git 的网络通信机制,Git 通过 HTTP 或 SSH 协议与远程服务器进行交互。在克隆过程中,Git 会根据远程版本库的结构,在本地重新构建对象数据库和引用,使得本地版本库与远程版本库在结构和数据上保持一致。

查看状态

在开发过程中,我们经常需要了解项目当前在版本控制方面的状态,例如哪些文件被修改了,哪些文件是新添加的等。git status 命令就可以帮助我们获取这些信息。

命令

git status

示例: 在一个已经初始化了 Git 版本库的 Node.js 项目中,假设我们修改了 app.js 文件,并新创建了一个 utils.js 文件,然后执行 git status 命令。

git status

输出可能如下:

On branch master
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:   app.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	utils.js

从输出中可以看到,app.js 文件被标记为已修改但未暂存,utils.js 文件被标记为未跟踪。这意味着 app.js 的修改还没有被准备好提交到版本库,而 utils.js 是一个全新的文件,Git 还不知道它的存在。这里的状态信息是基于 Git 对工作区、暂存区和版本库的对比得出的。工作区是我们实际进行代码开发的地方,暂存区是准备提交的文件的临时存放处,版本库则存储了项目的历史版本。

添加文件到暂存区

在将修改提交到版本库之前,需要先把文件添加到暂存区。这一步是告诉 Git 我们希望将这些文件的当前状态包含在下一次提交中。

命令

git add <文件名>

如果要添加所有修改和新文件,可以使用:

git add.

示例: 继续上面的例子,要将修改的 app.js 和新创建的 utils.js 文件添加到暂存区,可以执行:

git add app.js utils.js

或者使用 git add. 一次性添加所有:

git add.

当执行 git add 命令时,Git 会计算文件的哈希值(通常是 SHA - 1 哈希),并将文件的内容和元数据存储到对象数据库中。同时,在暂存区中记录下这些文件的信息,包括文件名、对应的对象哈希等。这样,在下一次提交时,Git 就可以根据暂存区的信息准确地记录项目的状态变化。

提交更改

将文件添加到暂存区后,就可以将这些更改提交到版本库中,形成一个新的版本记录。

命令

git commit -m "提交说明"

示例: 在将 app.jsutils.js 添加到暂存区后,执行以下提交命令:

git commit -m "Add utils.js and modify app.js"

提交时,-m 选项后面的字符串是提交说明,它应该简洁明了地描述本次提交所做的更改。提交过程中,Git 会创建一个新的提交对象,该对象包含了本次提交的作者信息、提交时间、提交说明以及指向暂存区中文件对象的指针。同时,提交对象还会指向其父提交对象(首次提交除外,首次提交没有父提交),通过这种链式结构,Git 构建出项目的版本历史。

查看提交历史

在项目开发过程中,我们经常需要回顾之前的提交记录,了解项目的演变过程。git log 命令可以帮助我们查看提交历史。

命令

git log

示例: 在一个有多次提交的 Node.js 项目中执行 git log 命令,输出可能如下:

commit 3a526a75c8e55d8f0a87c6a38d91c19c2b489c12
Author: Your Name <your_email@example.com>
Date:   Tue Jul 12 14:30:00 2023 +0800

    Add utils.js and modify app.js

commit 5f2c3a87d1f0e5c9d2c7a4d1b8e5d2f1d8e9c12f
Author: Your Name <your_email@example.com>
Date:   Mon Jul 11 10:15:00 2023 +0800

    Initial commit

从输出中可以看到每次提交的哈希值、作者、日期和提交说明。默认情况下,git log 会按照时间倒序显示提交记录,最新的提交在最上面。git log 命令还有很多选项可以帮助我们更灵活地查看提交历史。例如,使用 --oneline 选项可以以简洁的单行格式显示提交信息:

git log --oneline

输出类似:

3a526a7 Add utils.js and modify app.js
5f2c3a8 Initial commit

使用 --graph 选项可以以图形化的方式显示分支合并情况:

git log --graph

这在处理复杂的分支结构时非常有用。

撤销暂存区的更改

有时候,我们可能不小心将一些不需要的文件添加到了暂存区,或者想撤销之前的暂存操作。可以使用 git reset 命令来撤销暂存区的更改。

命令

git reset <文件名>

如果要撤销所有暂存区的更改,可以使用:

git reset

示例: 假设我们已经将 app.js 添加到了暂存区,但后来发现这个修改还不应该提交,想撤销暂存。执行以下命令:

git reset app.js

执行 git reset 命令时,如果指定了文件名,Git 会从暂存区中移除该文件的暂存状态,使其回到工作区修改但未暂存的状态。如果不指定文件名,git reset 会将暂存区重置为上一次提交时的状态,即移除所有已暂存的更改。这里需要注意的是,git reset 命令有不同的参数选项,如 --soft--mixed(默认)和 --hard,它们对工作区和暂存区的影响不同。--soft 仅重置 HEAD 指针,暂存区和工作区不受影响;--mixed(默认)重置 HEAD 指针并将暂存区恢复到上一次提交时的状态,但工作区的文件保持不变;--hard 不仅重置 HEAD 指针和暂存区,还会将工作区的文件恢复到上一次提交时的状态,这会丢失工作区未提交的更改,所以使用 --hard 选项时要格外小心。

撤销工作区的更改

如果在工作区对文件进行了修改,但又不想保留这些修改,可以使用 git checkout 命令撤销工作区的更改。

命令

git checkout -- <文件名>

示例: 假设我们在 app.js 文件中进行了一些修改,但现在想撤销这些修改,恢复到上次提交或暂存时的状态。执行以下命令:

git checkout -- app.js

执行该命令后,app.js 文件会恢复到上次提交或暂存时的内容。这里 git checkout 命令实际上是从暂存区或版本库中取出文件的副本,覆盖工作区中对应的文件。需要注意的是,这种撤销操作是不可逆的,如果没有备份,被撤销的修改将永久丢失。

创建分支

分支是 Git 中非常强大的功能,它允许我们在项目的不同方向上进行开发,而不会影响主分支的稳定性。

命令

git branch <分支名>

示例: 在一个 Node.js 项目中,假设我们要创建一个名为 feature - new - module 的分支用于开发新模块,执行以下命令:

git branch feature - new - module

执行此命令后,Git 会在当前版本库中创建一个新的分支,该分支指向与当前所在分支相同的提交对象。分支本质上是一个指向提交对象的指针,通过创建分支,我们可以在不同的指针(分支)上进行开发,从而实现并行开发不同的功能或修复不同的问题。

切换分支

创建分支后,我们需要切换到相应的分支才能在该分支上进行开发。

命令

git checkout <分支名>

从 Git 2.23 版本开始,也可以使用更简洁的命令:

git switch <分支名>

示例: 要切换到刚才创建的 feature - new - module 分支,执行:

git checkout feature - new - module

或者

git switch feature - new - module

切换分支时,Git 会更新 HEAD 指针,使其指向目标分支所指向的提交对象,并将工作区和暂存区的状态更新为该提交对象对应的状态。这样,我们就可以在新的分支上进行独立的开发,不会影响其他分支。

合并分支

当在一个分支上完成了某项功能开发或问题修复后,通常需要将该分支的更改合并到主分支或其他目标分支。

命令: 假设我们在 feature - new - module 分支上完成了开发,要将其合并到 master 分支。首先切换到 master 分支:

git checkout master

然后执行合并命令:

git merge feature - new - module

示例

git checkout master
git merge feature - new - module

执行合并操作时,Git 会找到两个分支的共同祖先提交对象,然后将 feature - new - module 分支相对于共同祖先的更改应用到 master 分支上。如果合并过程中没有冲突,Git 会自动创建一个新的合并提交对象,该对象有两个父提交对象,分别来自 master 分支和 feature - new - module 分支。如果存在冲突,Git 会暂停合并过程,并提示哪些文件存在冲突。我们需要手动解决这些冲突,修改冲突文件后,再执行 git addgit commit 完成合并。

解决合并冲突

在合并分支时,如果两个分支对同一文件的同一部分进行了不同的修改,就会产生合并冲突。

示例: 假设在 master 分支和 feature - new - module 分支中都修改了 app.js 文件的同一代码段。当执行 git merge feature - new - module 时,Git 会提示冲突:

Auto - merging app.js
CONFLICT (content): Merge conflict in app.js
Automatic merge failed; fix conflicts and then commit the result.

打开 app.js 文件,会看到类似如下的冲突标记:

<<<<<<< HEAD
// master 分支中的代码修改
console.log('This is from master branch');
=======
// feature - new - module 分支中的代码修改
console.log('This is from feature - new - module branch');
>>>>>>> feature - new - module

我们需要手动编辑 app.js 文件,解决冲突。例如,可以选择保留其中一个分支的修改,或者综合两个分支的修改:

// 综合两个分支的修改
console.log('This is from master branch and feature - new - module branch');

解决冲突后,执行 git add app.js 将修改后的文件添加到暂存区,然后执行 git commit 完成合并:

git add app.js
git commit -m "Merge branch 'feature - new - module' into master"

解决合并冲突需要对项目代码有深入的理解,确保合并后的代码能够正常运行。

删除分支

当一个分支的功能已经合并到目标分支,或者该分支不再需要时,可以将其删除。

命令

git branch -d <分支名>

如果要强制删除一个未合并的分支,可以使用:

git branch -D <分支名>

示例: 假设 feature - new - module 分支已经成功合并到 master 分支,现在要删除该分支,执行:

git branch -d feature - new - module

如果 feature - new - module 分支还未合并,但确定不再需要,可以使用强制删除命令:

git branch -D feature - new - module

执行删除分支命令时,Git 会删除指向该分支的指针。如果使用 -d 选项且分支未合并,Git 会提示错误,防止误删除未合并的重要分支。而 -D 选项会直接删除分支指针,无论分支是否合并,所以使用 -D 时要特别小心。

标签

标签是对某个特定提交的一个标记,常用于标记发布版本、重要里程碑等。

命令: 创建轻量级标签:

git tag <标签名>

创建附注标签:

git tag -a <标签名> -m "标签说明"

示例: 假设我们在项目开发到某个阶段,要标记一个发布版本 v1.0。如果创建轻量级标签,执行:

git tag v1.0

如果创建附注标签,执行:

git tag -a v1.0 -m "Release version 1.0"

轻量级标签只是一个指向提交对象的简单引用,而附注标签会创建一个独立的标签对象,包含标签作者、日期、标签说明等详细信息。标签创建后,可以通过 git tag 命令查看所有标签:

git tag

要查看某个标签的详细信息,可以使用:

git show <标签名>

例如:

git show v1.0

这对于回顾项目的发布历史和重要节点非常有帮助。

远程仓库操作

在实际开发中,我们通常会将本地版本库与远程代码托管平台(如 GitHub、GitLab 等)上的远程仓库进行交互。

添加远程仓库

git remote add <远程仓库别名> <远程仓库地址>

例如,将本地项目与 GitHub 上的远程仓库关联,远程仓库别名为 origin

git remote add origin https://github.com/username/nodejs_project.git

查看远程仓库

git remote -v

该命令会显示远程仓库的别名和对应的地址。

推送本地分支到远程仓库

git push <远程仓库别名> <本地分支名>:<远程分支名>

如果远程分支名与本地分支名相同,可以省略 :<远程分支名>。例如,将本地 master 分支推送到远程 origin 仓库的 master 分支:

git push origin master

从远程仓库拉取更新

git pull <远程仓库别名> <远程分支名>:<本地分支名>

如果本地分支名与远程分支名相同,可以省略 :<本地分支名>。例如,从远程 origin 仓库拉取 master 分支的更新到本地 master 分支:

git pull origin master

git pull 命令实际上是 git fetchgit merge 的组合。git fetch 会从远程仓库下载最新的提交对象和引用,但不会自动合并到本地分支。而 git pull 会在下载后自动将远程分支合并到本地分支。在实际使用中,为了避免不必要的合并冲突,建议在 git pull 之前先查看远程分支的更改情况,可以先执行 git fetch,然后使用 git log 等命令查看远程分支的更新,再决定是否进行合并。

总结常用命令组合场景

  1. 新功能开发流程

    • 创建新分支:git branch feature - new - feature
    • 切换到新分支:git checkout feature - new - featuregit switch feature - new - feature
    • 进行代码开发,修改文件
    • 添加修改到暂存区:git add.
    • 提交更改:git commit -m "Implement new feature"
    • 开发完成后,切换回主分支:git checkout mastergit switch master
    • 合并新分支到主分支:git merge feature - new - feature
    • 如果有冲突,解决冲突后,git add 冲突文件,然后 git commit
    • 删除已合并的新分支:git branch -d feature - new - feature
  2. 修复线上问题流程

    • 基于线上版本标签创建修复分支:git branch hotfix - bug - fix v1.0(假设线上版本标签为 v1.0
    • 切换到修复分支:git checkout hotfix - bug - fixgit switch hotfix - bug - fix
    • 修复代码中的问题
    • 添加修改到暂存区:git add.
    • 提交更改:git commit -m "Fix bug in v1.0"
    • 切换回主分支:git checkout mastergit switch master
    • 合并修复分支到主分支:git merge hotfix - bug - fix
    • 如果有冲突,解决冲突后,git add 冲突文件,然后 git commit
    • 切换到开发分支(假设为 develop):git checkout developgit switch develop
    • 合并修复分支到开发分支:git merge hotfix - bug - fix
    • 如果有冲突,解决冲突后,git add 冲突文件,然后 git commit
    • 删除修复分支:git branch -d hotfix - bug - fix

通过熟练掌握这些 Git 常用命令及其组合场景,在 Node.js 项目开发中能够更加高效地进行版本控制,确保项目的稳定性和可维护性,同时方便团队成员之间的协作开发。无论是小型项目还是大型项目,合理运用 Git 命令都能极大地提升开发效率和代码管理的质量。在实际应用中,还需要不断实践和总结经验,根据项目的具体需求和团队的开发习惯,灵活运用这些命令,以达到最佳的开发效果。同时,了解 Git 的底层原理,如对象数据库、提交对象结构等,有助于更好地理解和解决在使用过程中遇到的各种问题,进一步提升版本控制的能力。