杂项
开发
Git Workflow

一套常用的工作流

Git 可以分为 RemoteLocal ,其中 Remote 代表远程仓库比如 Github, Local 又可以分为两个部分,一个部分就是我们拉下来的 Local git,另一个部分则是Disk 磁盘部分,这部分是我们源文件真正存在磁盘里面的样子,我们用 VSCODE 之类的编辑器修改都是在这个部分进行的。

初始状态:

  • Remote
    • main(master)
      • Initial commit
  • Local
    • main(master)
      • Initial commit
  • Disk
    • main(master)
      • Initial commit

1. 本地修改

在我们要修改代码的时候,第一件事是建立一个新的 feature branch(名字自定),然后在这个分支上进行修改,而不是直接在 main 分支上进行修改,这样做的好处是,它可以让我们在修改的时候,不会影响到其他人的工作,也不会影响到 main 分支,这样就可以保证 main 分支的稳定性。

git checkout -b feature-branch

这时我们的状态应该是这样的:

  • Remote
    • main(master) 这个分支一般被认为是公共的分支,所以不要在这个分支上直接进行修改
      • Initial commit
  • Local
    • main(master)
      • Initial commits
    • feature-branch 这个分支是我们自己建立的,认为是个人的部分,用来进行修改的
      • Initial commit
  • Disk
    • feature-branch
      • Initial commit -> ...changes...(还未放入暂存区)

2. 将修改真正放到 git 里面

在使用 git add <changed_file> 放入暂存区之前,推荐先使用 git diff 查看修改的内容,之后在用 git add <changed_file>告知 git 修改了的部分,最后用 git commit 来把修改真正放到 git 里面。

此时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit
  • Local
    • main(master)
      • Initial commits
    • feature-branch
      • Initial commit -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> changed-commit(实际上 Disk 是没有 commit 概念的,这里这样写只是为了方便理解)

3. 将修改的分支推送到远程仓库

git push origin feature-branch

此时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit
    • feature-branch
      • Initial commit -> changed-commit
  • Local
    • main(master)
      • Initial commits
    • feature-branch
      • Initial commit -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> changed-commit

4. 合并分支

在我们合并分支之前,我们经常会遇到这样的情况,就是 main(master) 分支上的代码已经更新了,而我们的 feature-branch 分支上的代码还是旧的,这时候我们就需要先将 main 分支上的代码拉下来。首先我们需要切换到 main 分支上(git checkout main),然后使用 git pull origin main 来拉取 main 分支上的代码,这时我们的状态应该是这样的:

此时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit -> update1
    • feature-branch
      • Initial commit -> changed-commit
  • Local
    • main(master)
      • Initial commits -> update1
    • feature-branch
      • Initial commit -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> changed-commit

然后我们要用 git checkout feature-branch 回到我们的 feature-branch 分支上,然后使用 git rebase main 或者 git merge main 来合并 main 分支上的代码,如果有冲突代码的部分,我们需要手动选择需要留下的部分。

这时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit -> update1
    • feature-branch
      • Initial commit -> changed-commit
  • Local
    • main(master)
      • Initial commits -> update1
    • feature-branch
      • Initial commit -> update1 -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> update1 -> changed-commit

5. 将合并后的分支推送到远程仓库

git push -f origin feature-branch

因为我们使用了 rebase 或者 merge 修改了 commit 的历史,所以我们需要使用 -f 参数来强制推送。

此时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit -> update1
    • feature-branch
      • Initial commit -> update1 -> changed-commit
  • Local
    • main(master)
      • Initial commits -> update1
    • feature-branch
      • Initial commit -> update1 -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> update1 -> changed-commit

6. 合并(PR)分支到主分支

我们可以在 github 上使用 New pull request 按钮,将我们的分支合并到主分支上。在项目的维护者审查完代码之后,一般情况下会使用 Squash and merge 按钮来合并分支。因为我们新增的 Commit 可能会有很多,这时候我们希望我们的 main(master) 分支尽可能的简洁,所以我们会将多个 Commit 合并成一个 Commit。

此时我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit -> update1 -> update2
    • feature-branch
      • Initial commit -> update1 -> changed-commit
  • Local
    • main(master)
      • Initial commits -> update1
    • feature-branch
      • Initial commit -> update1 -> changed-commit
  • Disk
    • feature-branch
      • Initial commit -> update1 -> changed-commit

一般情况下,合并完成之后我们就可以删除我们的 feature-branch 分支了,在 github 上有个 Delete branch 按钮,我们可以使用这个按钮来删除我们的分支。接下来是删除本地的分支,我们先使用 git checkout main 切换到 main 分支上,然后使用 git branch -D feature-branch 来删除本地的分支。最后使用 git pull origin main 来更新本地的代码。

最后我们的状态应该是这样的:

  • Remote
    • main(master)
      • Initial commit -> update1 -> update2
  • Local
    • main(master)
      • Initial commits -> update1 -> update2
  • Disk
    • main(master)
      • Initial commits -> update1 -> update2