0%

git 实操记录

2023.7.10 入职距今已经两个月零 3 天了,培训课程十分紧张也没来得及做一些技术的思考和整理。主要是下班回家后只想躺着玩手机,周末持续性出去撒欢。 但只学习不思考和整理是程序员的忌讳。培训课程结束后,会对这两个月的培训时间进行思考,同时对未来该怎么更好的工作也进行一个思考,甚至包括如何更好的休息锻炼来保持充沛的精力。

回到正文,git 是程序员写框架和交流代码时的必要工具,而过于贫瘠的实操经验导致我真的不会这玩意。尤其是多人协作 pull, merge 或者 reset 时,时常把代码搞的乱七八糟。所以在这里记录 git 的踩坑记录。

git 操作时很大程度受限于实际的情景,本地基于什么分支进行了什么修改,是否暂存,是否提交,是否有冲突等等等等。出问题后去网上搜索时,网上的例子和本地的例子不一定很符合,或者说只有一半符合。往往不知道该执行哪些命令,是否会把文件弄的很乱无法撤回。

这个时候建议把实际情景描述一下,去问问 GPT,以我的使用经验,得到的回答 99.9% 都是可用的。

git 开发时,A 分支的代码泄漏到了 B 分支 ?

问题背景

当时想实现 master 分支只有 README.md, .gitignore, 3rdparty 等公共文件。

  • 对于任务一,新建 dev1 分支,并在 dev1 文件夹里面写代码
  • 对于任务二,新建 dev2 分支,并在 dev2 文件夹里面写代码

这样 dev1dev2 分支的代码位于不同文件夹,互不干扰。最后全部合并到 master 分支的时候,也不会产生冲突。

错误操作

在实现期间出现了一个漏洞,当完成 dev1 任务的代码后,直接在 dev1 分支下 git checkout -b dev2,这样就会发生:dev2 分支下有 dev1 的代码,不是很优雅。

当时培训课程的进度比较紧张,也没有刻意去关注这个问题。只是在 dev2 分支下手动删除了 dev1 文件夹的代码,这样在 git status 的时候会看到很多 delete 信息,且会随着 dev2 分支的提交而提交到 gitlab 中,merge 时会看到很多无用的删除文件信息。

正确做法

随着课程的陆续学习,框架规模越来越大,代码文件也越来越复杂。由于自己的 git 实操很少,担心 git 误操作后导致分支或文件过于混乱。又回过头来重新看这一问题,在本地进行一些简单的实验后发现了正确做法。

在完成 dev1 分支的代码并提交后,应该 git checkout master,在 master 分支下新建 dev2 分支,这样才能实现 dev2 分支不含 dev1 的代码,保证提交代码时的信息足够干净。

记一次代码污染

背景

起因:需求是将本地 local 分支提交到 develop 分支。我理解成了将本地的 local 分支提交到 develop 分支,并向 master 提交 PR。于是执行了:

1
git push -u origin local:develop

这样就导致了代码污染。因为可能有其他人基于 develop 分支开发代码,而我的 local 代码直接覆盖了远程的 develop 代码。

  • 其他人提交代码的时候,会导致代码冲突;
  • 其他人获取 develop 代码时,会获取到我的 local 代码,但是我的 local 代码没有经过检查和测试,负责模块整合的人也没有处理我这个模块可能存在的异常。所以很可能在运行期间存在错误。

正确做法

1
git push -u origin local

这样远程仓库中就会有一个 local 分支,提交 PR 时将 local 分支提交到 develop 分支即可。为什么要添加 -u 参数?

如果你在本地仓库中使用 git clone 命令克隆了一个远程仓库,并在本地仓库中使用 git checkout -b A 命令创建了一个名为 A 的新分支,并使用 git push A 命令将该分支推送到远程仓库,那么远程仓库将会有一个名为 A 的分支。

但是在使用 git push 命令时,你需要指定要推送的分支和远程仓库的名称。如果你使用 git push A 命令,git 将会尝试将本地仓库中名为 A 的分支推送到远程仓库中名为 A 的分支,但是如果远程仓库中不存在名为 A 的分支,git 将会报错。

因此,如果你想要将本地仓库中的 A 分支推送到远程仓库,并且希望在远程仓库中创建一个名为 A 的分支,应该使用以下命令:

1
git push -u origin A

这将会将本地仓库中的 A 分支推送到名为 origin 的远程仓库,并在远程仓库中创建一个名为 A 的分支。

使用代码回撤来解决代码污染

但是现在已经做错了,需要使用代码回撤来修复污染。可以使用 git reflog 命令查看本地仓库的提交历史,找到 develop 分支的提交记录。使用git reset 命令将代码重置到 develop

1
2
3
4
5
6
7
8
9
10
11
$ git reflog

...
HEAD@{1}: commit: <commit message>
HEAD@{2}: commit: <commit message>
HEAD@{3}: commit: <commit message>
HEAD@{4}: commit: <commit message>
HEAD@{5}: commit: <commit message>
HEAD@{6}: commit: <commit message>
HEAD@{7}: commit: <commit message>
...

找到最后一个 develop 分支的提交记录,记下该提交的哈希值。运行 git reset 命令将本地仓库的 develop 分支重置到该提交记录。例如,如果最后一个 develop 分支的提交记录的哈希值为 abc123,则可以运行以下命令:

1
$ git reset --hard abc123

运行 git push --force 命令将本地仓库的 develop 分支强制推送到远程仓库。请注意,这将覆盖远程仓库中的 develop 分支,因此请确保已经找到了正确的提交记录。这样就能恢复 develop 分支之前的代码。

1
$ git push --force origin develop

git 实用命令

一般的开发流程

首先克隆仓库

1
git clone git@xxx.git

创建本地分支,并对应远程分支

1
2
3
git branch -a         // 查看分支
git checkout -b local_branch remote_branch // 切换分支并对应远程分支

获取新分支

clone 仓库的 1 天后,有新分支提交到了远程仓库,所以本地没有这个分支。为了查看新分支的代码,需要更新分支:

1
git remote update origin -p

暂存修改

在新分支开发代码时,遇到紧急任务需要切换到其他分支修复漏洞。但是新分支的代码才写了一点点还没有 commit,如果直接 git checkout 会报错,因为新分支的修改没有被存下来或提交。此时可以暂存修改:

1
2
git stash                  // 暂存当前未提交的更改
git checkout <branch_name> // 切换到另一个分支

当你完成其他工作并切换回原分支时,可以使用以下命令还原暂存的更改:

1
git stash pop

不建议以下的操作,因为这会直接放弃当前分支的修改:

1
git checkout -f <branch_name> // 切换到另一个分支并丢弃未提交的更改

git 丢弃本地的修改

代码改的乱七八糟不想要了:

1
git reset --hard HEAD

临时代码推送

临时创建了一个文件夹复现了某个问题,需要把这份代码提交到某个仓库。在 git init 之后增加远程仓库:

1
git remote add origin git@xxx:xxx.git

因为是临时新建的仓库,所以目前处于 master 分支。执行下面命令,将本地的 master 分支推送到远程的 test 分支(远程没有的话会自动创建):

1
git push origin master:test     // 不加 master: 会报错,因为本地没有 test 分支

修改错别字,不值得重新 commit

首先修改小错误,然后:

1
2
git add .
git commmit --amend

如果此时直接 push 会报错,因为 git status 显示并没有新的内容。如果是提交到自己的分支,在不影响他人的开发的情况下可以直接:

1
git push origin master:test -f

这样仓库上只显示一次 commit 记录。如果不是强制推送,那么会遇到下面的问题:

1
2
3
4
5
6
7
To git@github.xxxx.git
! [rejected] master -> main (non-fast-forward)
error: failed to push some refs to 'git@github.xxxx.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

起因是在这次 push 之前有一次 git commit --amend 修改错别字的操作,当时这个修改是没有提交的。所以再次修改代码并提交时,就遇到了冲突。因为同一文件同样的位置有不同的内容,无法自动合并,所以 push 的时候报错。

此时需要手动 git pull 一下,由用户自己手动 merge 处理冲突。如果是 vscode 的话,看一下哪里修改,如果保留当前版本,点击 accept current change 即可。再次 git add commit push 就没问题了。

代码写到一半,需要同步同事的代码

此时只需要在当前分支下 pull 代码。把自己的代码完成后,再次提交到分支。假设远程分支叫 B,基于 B 分支 checkout -bA 分支,在 A 分支写代码。远程分支有更新, merge 了一些修改,让 A 获取到 B 的更新:

1
git pull origin B

git 查看本地分支对应的远程分支名

1
git branch -vv

git 查看分支差异

git 基于 B 分支创建了分支 A,并在 A 分支进行了修改和提交,提交后,vscode 等编辑器内无法看到修改内容。可以通过下述命令查看 A 分支和 B 分支的差异,也就是看 A 分支都改动了哪里。

1
git diff A B file_path

多次 commit 记录合并

为了保证提交信息的整洁,可以使用 git rebase 命令来将多个 commit 合并成一个,并保留代码的修改。以下是具体步骤:

  1. 使用 git log 命令查看你想要合并的 commit 记录的哈希值,例如将以下 3 个 commit 记录合并成一个:

    1
    2
    3
    4
    $ git log --oneline
    3a2b1c3 Add feature A
    2b3c4d5 Fix bug B
    1c2d3e4 Implement feature C
  2. 使用 git rebase -i HEAD~3 命令来打开交互式 rebase 编辑器,其中 HEAD~3 表示要合并的 commit 记录数量。在编辑器中,将第二个和第三个 commit 记录的操作改为 squash,表示将它们合并到第一个 commit 记录中。例如:

    1
    2
    3
    pick 3a2b1c3 Add feature A
    squash 2b3c4d5 Fix bug B
    squash 1c2d3e4 Implement feature C

    保存并关闭编辑器。

pick 操作会将一个提交应用到当前分支,而 squash 操作会将一个提交合并到前一个提交中,从而将多个提交合并成一个。

  1. git 会自动打开另一个编辑器,让你编辑合并后的 commit 信息。你可以保留第一个 commit 记录的信息,或者修改为新的 commit 信息。保存并关闭编辑器。

  2. 使用 git push --force 命令将修改后的 commit 记录推送到远程仓库。注意,由于使用了 --force 参数,这会覆盖远程仓库中的历史记录,因此请确保你的操作不会影响其他人的工作。

git reset 用法

git reset 命令用于将当前分支的 HEAD 指针移动到指定的提交,同时可以选择是否修改暂存区和工作目录。--hard--softgit reset 命令的两个选项,它们的区别在于是否修改暂存区和工作目录。

  • --hard 选项会将 HEAD 指针、暂存区和工作目录都重置为指定的提交。这意味着所有未提交的更改都会被丢弃,工作目录中的文件会被覆盖为指定提交中的文件。

  • --soft 选项只会将 HEAD 指针移动到指定的提交,而不会修改暂存区和工作目录。这意味着所有未提交的更改都会保留在工作目录中,可以通过 git status 命令查看它们的状态。

一般来说,如果你想完全撤销所有未提交的更改并回到指定的提交,可以使用 --hard 选项。如果你只是想将 HEAD 指针移动到指定的提交,但保留未提交的更改,可以使用 --soft 选项。

这个命令我用的不多,实际场景用到时在补充。

感谢上学期间打赏我的朋友们。赛博乞讨:我,秦始皇,打钱。

欢迎订阅我的文章