查看原文
其他

如何让你的 Git 历史保持“干净”?!

Manuel Sidler 脚本之家 2021-06-30

脚本之家

你与百万开发者在一起

消除 Git 历史的最佳手段有哪些?

作者 | Manuel Sidler

译者 | 谭开朗,责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

以下为译文:

使用Git已有几年的时间了,我必须承认,干净的提交历史并不总是那么重要。我们从《回到未来》中知道,改写历史可能会造成某些糟糕的后果。我只能假设,这就是为什么这是一个可怕的话题。在这篇文章中,我想分享一些基本的命令,这些命令将帮助你保持Git历史的整洁,并消除《回到未来》中的糟糕后果。


1


要事第一


本文中的所有命令都将生成新的提交哈希码,从而将其与原始分支区别开来。这意味着,你必须使用git push -force或git push -f强制覆盖远程上的历史记录。这又意味着:永远不要更改共享分支上的git历史记录。如果远程分支有新的提交,则有一个更安全的命令,它甚至可以拒绝强制推送:git push –force-with-lease。


2


场景1:在最后一次提交中添加内容


每个人都有过这样的经历:将改动添加到暂存区,提交并等待构建。但不幸的是,构建失败了。哦,你忘了添加文件x。接下来会发生什么?将文件x添加到暂存区,并提交一条类似于“愚蠢的我忘了添加文件x”的内容。请不要这么做!让我来介绍第一个命令:

git commit -amend

该命令将暂存区的改动添加到最近一次提交,并支持更改最近一次的提交内容。使用以下简单的命令也能达到相同的效果:

git commit –amend -m“new message”

如果不想修改最后的提交信息,可以添加no-edit参数:

git commit --amend --no-edit

所以不要再犯“愚蠢的我忘了…”的错误了!


3


Git的交互式rebase


在接下来的几个场景中,我们将使用交互式git rebase。这个工具能帮助修改历史上更早的更改。只需使用以下命令启动一个交互式rebase:

git rebase –i <base>

其中<base>表示要重写历史的节点。

例如,重写最后三次提交:

git rebase -i HEAD~3

另一个例子,重写历史到一个特定的提交:

git rebase -i 63a2356

该命令显示了配置编辑器的提交和选项:

pick bcfd87e add sql scripts for database
pick 9fb0b9c prevent users from changing their email
pick e0b46b9 cleanup web config

# Rebase dfef724..e0b46b9 onto dfef724 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

让我们进入第一个rebase场景。


4


场景2:向历史记录中的任意提交添加内容


就像在场景1中,我们忘记在提交中添加内容。但是,与其添加到最后一次提交中,不如将改动修改为历史上更远的一次提交。对于这种情况,交互式rebase为我们提供了编辑选项。

我们从交互式rebase命令开始,然后在我们想要更改的提交上设置编辑命令:

pick bcfd87e add sql scripts for database
edit 9fb0b9c prevent users from changing their email
pick e0b46b9 cleanup web config

交互式rebase停止此提交,我们可以添加更改:

Stopped at 9fb0b9c...  prevent users from changing their email
You can amend the commit nowwith

  git commit --amend 

Once you are satisfied with your changes, run

  git rebase --continue

完成后,只需将更改添加到暂存区,并使用amend命令提交:

git commit --amend

几乎完成了!现在我们要continue rebase:

git rebase –continue


5


场景3:合并提交


尽量多做合并。这意味着功能分支中的git历史记录通常是这样的:

9edf77a more review findings
67b5e01 review findings
940778d enable users to change their name
dc6b0db enable users to change their name
dfdd77d wip

这在特性开发期间可能很有用,但并不适用于整个git存储库历史。因此将所有提交合并为一个。有两种方式:squash和fixup。这两个命令都是将提交合并到前一个命令中。唯一的区别是,squash支持编辑新的提交内容,而fixup不支持。

我们来squash一些提交。我们像之前一样启动交互式rebase,并设置适当的选项:

pick dfdd77d wip
squash dc6b0db enable users to change their name
squash 940778enable users to change their name
squash 67b5e01 review findings
squash 9edf77a more review findings

# Rebase 63a2356..9edf77a onto 63a2356 (5 commands)

现在Git提供了所有消息的概览:

# This is a combination of 5 commits.
# This is the 1st commit message:

wip

# This is the commit message #2:

enable users to change their name

# This is the commit message #3:

enable users to change their name

# This is the commit message #4:

review findings

# This is the commit message #5:

more review findings

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

删除所有行,只将我们想要的信息写在最后:

enable users to change their name

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

瞧,把提交压缩成一个了:

cb88cf6 enable users to change their name

我们可以使用fixup命令执行同样的操作。在下面的场景中,提交消息很完美,我想把提交合并到:

pick dc6b0db enable users to change their name
fixup dfdd77d wip
fixup 940778enable users to change their name
fixup 67b5e01 review findings
fixup 9edf77a more review findings

# Rebase 63a2356..9edf77a onto 63a2356 (5 commands)

结果和上面squash的例子一样:

b8e76d1 enable users to change their name


6


场景4:分割提交


我们常常把两个或两个以上不同的主题合并在一起:

7080968 add sql scripts for database
172db2b prevent user from changing their email and cleanup web config

在这种情况下,将web配置的清理分离出来会更干净,对吧?此时,我们可以再次利用edit命令。使用互动rebase可做到这一点:

pick 7080968 add sql scripts for database
edit 172db2b prevent user from changing their email and cleanup web config

# Rebase dfef724..172db2b onto dfef724 (2 commands)

正如我们所期望的,Git在提交时停止了。现在我们可以把更改带回工作区域:

git reset HEAD~

接下来很简单,只需为更改创建两个提交:

git add [files]
git commit -m "prevent user from changing their email"
git add [files]
git commit -m "cleanup web config"

别忘了继续rebase:

git rebase --continue

结果如下:

9fb0b9c prevent user from changing their email
dfef724 cleanup web config
7080968 add sql scripts for database

多整洁!


7


场景5:重新排序提交


如果合并两个或多个提交,但它们的顺序不对怎么办?

09f43c9 validate user inputs
62490ed import user data
c531f57 validate user inputs

只需在rebase编辑器中重新排序提交,然后再使用fixup或squash合并它们。

pick 62490ed import user data
pick c531f57 validate user inputs
fixup 09f43c9 validate user inputs

# Rebase 6c70ff2..09f43c9 onto 6c70ff2 (3 commands)


8


场景6:更改提交消息


不满意特定的提交内容?可以使用reword命令随时更改它:

reword c531f57 validate user inputs
pick 62490ed import user data

# Rebase 6c70ff2..09f43c9 onto 6c70ff2 (3 commands)

Git将在此时停止提交,我们可以选择更改消息: 

validate user inputs

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.


9


场景7:删除提交


需要完全恢复特定的提交吗?在这种情况下,我们可以使用drop命令:

pick bcfd87e add sql scripts for database
drop 9fb0b9c prevent users from changing their email
pick e0b46b9 cleanup web config

# Rebase dfef724..e0b46b9 onto dfef724 (3 commands)

在这里,我们知道了保持Git历史记录整洁的重要性。假设我们将不同的特性放入一个提交中,或者将一个特性拆分为多个(无意义的)提交,那么还原要复杂得多。 


111111110


当事情出现问题时


在重写Git历史时,不要担心会破坏某些东西。

首先,我们总是可以使用git rebase--abort中止交互式rebase会话。 

这个命令将停止rebase会话并恢复所有更改。

其次,即使已经完成了一个rebase并把它搞砸了,我们也可以还原它。幸运的是,Git跟踪执行所有命令,我们可以使用git reflog打开日志。

e0b46b9 (HEAD -> feature/my2, feature/my3) HEAD@{34}: rebase -i (finish): returning to refs/heads/feature/my2
e0b46b9 (HEAD -> feature/my2, feature/my3) HEAD@{35}: commit: cleanup web config
9fb0b9c HEAD@{36}: commit: prevent users from changing their email
bcfd87e HEAD@{37}: reset: moving to HEAD~
3892bc7 HEAD@{38}: rebase -i: fast-forward
bcfd87e HEAD@{39}: rebase -i (start): checkout master
3892bc7 HEAD@{40}: rebase -i (finish): returning to refs/heads/feature/my2
3892bc7 HEAD@{41}: commit (amend): prevent user from changing their email and cleanup web config
39262b5 HEAD@{42}: rebase -i: fast-forward
bcfd87e HEAD@{43}: rebase -i (start): checkout master
39262b5 HEAD@{44}: rebase -i (abort): updating HEAD
39262b5 HEAD@{45}: rebase -i (abort): updating HEAD
bcfd87e HEAD@{46}: reset: moving to HEAD~
39262b5 HEAD@{47}: rebase -i: fast-forward
bcfd87e HEAD@{48}: rebase -i (start): checkout master
39262b5 HEAD@{49}: rebase -i (finish): returning to refs/heads/feature/my2
39262b5 HEAD@{50}: rebase -i (pick): prevent user from changing their email and cleanup web config
bcfd87e HEAD@{51}: commit (amend): add sql scripts for database
7080968 HEAD@{52}: rebase -i: fast-forward
dfef724 (master) HEAD@{53}: rebase -i (start): checkout master
172db2b (feature/my) HEAD@{54}: checkout: moving from feature/my to feature/my2
172db2b (feature/my) HEAD@{55}: commit: prevent user from changing their email and cleanup web config
7080968 HEAD@{56}: commit: add sql scripts for database
dfef724 (master) HEAD@{57}: checkout: moving from master to feature/my
dfef724 (master) HEAD@{58}: commit (initial): init

我们可以找到交互式rebase会话之前的最后一个操作,并将其恢复状态。例如:

git resthard HEAD@{18}

所以,请战胜恐惧,并保持Git历史的干净吧!

原文:https://dev.to/manuelsidler/keep-your-git-history-clean-101-k7

本文为 CSDN 翻译,转载请注明来源出处。

【END】



更多精彩


在公众号后台对话框输入以下关键词

查看更多优质内容!


女朋友 | 大数据 | 运维 | 书单 | 算法

大数据 | JavaScript | Python | 黑客

AI | 人工智能 | 5G | 区块链

机器学习 | 数学 | 留言送书

●  经典算法题:数组重新组合求最小值(优酷)

●  脚本之家粉丝福利,请查看!

●  那些裸辞的程序员,都干嘛去了?

● 超实用:14种性能监控与负载测试工具

● 作为程序员,我在电脑上都装过哪些 Chrome 插件?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存