压缩 Git 提交的快速指南
方法一:一次提交统治主分支
方法#2:没那么多!
方法三:挑剔
首先,让我们先搞清楚一件事:为了拥有一棵漂亮的树而重写 Git 历史记录,尤其是在公共仓库中,通常是不可取的。这有点像回到过去,你对自己项目版本所做的更改,会导致它看起来与别人从你现在已经删除的某个历史点 fork 出来的版本完全不同——我的意思是,你没看过《回到未来 第二部》吗?(如果你想坚持认为《回到未来》只拍过一部,这样你就不用再看续集了,我理解。)
重点来了。如果你把一些杂乱的提交推送到公共仓库,我建议你直接去处理,别再纠结了。(我们都会从尴尬中吸取教训,尤其是公开的尴尬——我说的就是你,过去的维多利亚。)如果你的杂乱提交目前只存在于你的本地版本,那就太好了!我们可以把它们整理成一个干净、描述清晰的提交,我们会很自豪地推送它,而且不会有人觉得你有什么问题。
有几种不同的方法可以压缩提交,选择合适的方法取决于我们需要实现的目标。
以下示例使用 进行演示git log --graph
,并附带一些简洁的选项。我们可以设置一个方便的别名,以便在终端中查看此日志格式:
git config --global alias.plog "log --graph --pretty=format:'%h -%d %s %n' --abbrev-commit --date=relative --branches"
然后我们只需git plog
查看漂亮的日志即可。
方法一:一次提交统治主分支
这适用于以下情况:
- 我们直接提交到 master
- 我们不打算打开合并功能请求
- 我们不想保留尚未推送的分支或变更的历史记录
此方法采用如下所示的 Git 树:
* 3e8fd79 - (HEAD -> master) Fix a thing
|
* 4f0d387 - Tweak something
|
* 0a6b8b3 - Merge branch 'new-article'
|\
| * 33b5509 - (new-article) Update article again again
| |
| * 1782e63 - Update article again
| |
| * 3c5b6a8 - Update article
| |
* | f790737 - (master) Tweak unrelated article
|/
|
* 65af7e7 Add social media link
|
* 0e3fa32 (origin/master, origin/HEAD) Update theme
并使其看起来像这样:
* 7f9a127 - (HEAD -> master) Add new article
|
* 0e3fa32 - (origin/master, origin/HEAD) Update theme
方法如下——抓住你的悬浮滑板,这非常复杂:
git reset --soft origin/master
git commit
好的,就这些。我们可以用 删除不需要的分支git branch -D new-article
。
方法#2:没那么多!
这适用于以下情况:
- 我们希望压缩最后x 个提交,但不是所有提交,因为
origin/master
- 我们想打开一个拉取请求来合并一个分支
此方法采用如下所示的 Git 树:
* 13a070f - (HEAD -> new-article) Finish new article
|
* 78e728a - Edit article draft
|
* d62603c - Add example
|
* 1aeb20e - Update draft
|
* 5a8442a - Add new article draft
|
| * 65af7e7 - (master) Add social media link
|/
|
* 0e3fa32 - (origin/master, origin/HEAD) Update theme
并使其看起来像这样:
* 90da69a - (HEAD -> new-article) Add new article
|
| * 65af7e7 - (master) Add social media link
|/
|
* 0e3fa32 - (origin/master, origin/HEAD) Update theme
为了将分支上的最后五次提交压缩new-article
为一次,我们使用:
git reset --soft HEAD~5
git commit -m "New message for the combined commit"
其中--soft
,我们的文件保持不变并处于暂存状态,5
可以被认为是“我想要合并的先前提交的数量”。
然后我们就可以git merge master
创建我们的拉取请求。
方法三:挑剔
假设我们度过了一个非常混乱的下午,我们的 Git 树如下所示:
* dc89918 - (HEAD -> master) Add link
|
* 9b6780f - Update image asset
|
* 6379956 - Fix CSS bug
|
* 16ee1f3 - Merge master into branch
|\
| |
| * ccec365 - Update list page
| |
* | 033dee7 - Fix typo
| |
* | 90da69a - Add new article
|/
|
* 0e3fa32 - (origin/master, origin/HEAD) Update theme
我们希望保留部分历史记录,但清理提交。我们还想更改部分提交的消息。为此,我们将使用git rebase
。
这适用于以下情况:
- 我们只想压缩一些提交
- 我们想要编辑之前的提交信息
- 我们想要删除或重新排序特定的提交
Gitrebase
是一款功能强大的工具,一旦掌握了它,就会非常方便。要更改自 以来的所有提交origin/master
,我们执行以下操作:
git rebase -i origin/master
或者,我们可以这样做:
git rebase -i 0e3fa32
其中提交哈希是我们希望保留的最后一次提交。
该-i
选项允许我们运行交互式 rebase 工具,它会启动我们的编辑器,本质上是一个供我们修改的脚本。我们将看到与 git log 中相反顺序的提交列表,最早的提交位于顶部:
pick 90da69a Add new article
pick 033dee7 Fix typo
pick ccec365 Update list page
pick 6379956 Fix CSS bug
pick 9b6780f Update image asset
pick dc89918 Add link
# Rebase 0e3fa32..dc89918 onto 0e3fa32 (6 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# 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
#
~
这些注释为我们提供了便捷的指南,告诉我们可以做什么。现在,让我们将小改动的提交压缩成更重要的提交。在编辑器中,我们将脚本修改如下:
pick 90da69a Add new article
squash 033dee7 Fix typo
pick ccec365 Update list page
squash 6379956 Fix CSS bug
squash 9b6780f Update image asset
squash dc89918 Add link
保存更改后,交互式工具将继续运行。它将按顺序执行我们的指令。在这种情况下,我们再次看到编辑器,其中包含以下内容:
# This is a combination of 2 commits.
# This is the 1st commit message:
Add new article
# This is the commit message #2:
Fix typo
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 0e3fa32
# Last commands done (2 commands done):
# pick 90da69a Add new article
# squash 033dee7 Fix typo
# Next commands to do (4 remaining commands):
# pick ccec365 Update list page
# squash 6379956 Fix CSS bug
# You are currently rebasing branch 'master' on '0e3fa32'.
#
# Changes to be committed:
# modified: ...
#
~
如果我们愿意的话,现在是时候为这第一个 squash 创建新的提交消息了。保存后,交互式工具将进入下一个指令。除非……
[detached HEAD 3cbad01] Add new article
1 file changed, 129 insertions(+), 19 deletions(-)
Auto-merging content/dir/file.md
CONFLICT (content): Merge conflict in content/dir/file.md
error: could not apply ccec365... Update list page
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply ccec365... Update list page
再次强调,该工具提供了一些非常有用的说明。一旦我们解决了合并冲突,就可以使用 继续该过程git rebase --continue
。我们的交互式 rebase 会从中断的地方继续执行。
一旦所有压缩完成,我们的 Git 树看起来如下所示:
* 3564b8c - (HEAD -> master) Update list page
|
* 3cbad01 - Add new article
|
* 0e3fa32 - (origin/master, origin/HEAD) Update theme
呼,好多了。
这篇文章是从我的博客上关于 Git 提交实践的一篇较长的文章中精心摘录的。
文章来源:https://dev.to/victoria/a-quick-guide-to-squashing-git-commits-7io