本文主要介绍Git的一些进阶技巧命令的使用。
定制专属的快捷命令
掌握Git小技巧,设置别名,简化操作。 通过git config
命令为常用Git指令设定简短别名。
# 如设置co别名用于checkout
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci "commit -s"
git config --global alias.st status
比如,输入git ci
即可代替冗长的git commit -s
。随着Git使用深入,不妨为常用命令创建别名。例如,为简化取消暂存文件的操作,可自定义一个Git别名。
git config --global alias.unstage 'reset HEAD --'
以下是两种常用的方法,主要解决将文件从暂存区移除:
# 方法一: 适用于单个文件或多文件的情况。
git reset HEAD -- fileA
# 方法二: 虽然Git没有直接的unstage命令,可通过别名来简化操作。
git unstage fileA
您可以使用git last
来代替git log -1 HEAD
命令,以查看最近一次的提交记录。
git config --global alias.last 'log -1 HEAD'
这样,可以轻松地看到最后一次提交信息:
# 这个命令是为Git配置一个全局别名last,使每次输入git last就能显示最近一次的提交信息。
git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646 Author: Josh Goebel <dreamer3@example.com> Date: Tue Aug 26 19:48:51 2008 +0800 test for current head Signed-off-by: Scott Chacon <schacon@example.com>
代码合并与变基
在 Git 中整合来自不同分支的修改主要有两种方法:合并(merge) 以及变基(rebase)。
合并:对于两个分支,如下图:
整合分支最容易的方法是 Merge 命令。 它会把两个分支的最新快照(C3和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交)
Rebase合并
通过提取在 C4 中引入的补丁和修改,然后在 C3的基础上应用一次。 在 Git 中,这种操作就叫做变基。 您可以使用 rebase命令将提交到某一分支上的所有修改都移至另一分支上。
在上面这个例子中,运行:
git checkout experiment git rebase master First, rewinding head to replay your work on top of it... Applying: added staged command
它的原理是首先找到这两个分支(即当前分支 Experiment、变基操作的目标基底分支 Master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。
现在回到master分支,进行一次快进合并。
# 切换到Git仓库的master分支。 git checkout master # 合并当前分支到已检出的分支。在执行git merge之前,确保您已经切换到了想要合并到的目标分支。 git merge experiment
优雅地合并分支代码并提交
对比两种合并方法,rebase能让提交历史更整洁,呈现串行趋势,因此备受青睐。它不仅能优雅地合并代码,还能修改提交历史。通过rebase,您可以将本地多个开发提交合并,再整合到目标分支,使历史记录更加清晰。
代码暂存
工作时,当您忙碌于项目某部分时,而这时想要切换到另一个分支做一点别的事情。 若需临时转至另一分支,当下半成品提交显得多余, 这时执行git stash
命令可以将未完成的修改保存到一个栈上,而您可以随时重新应用这些改动切换分支。
以下为例,进入项目查看之前改动的文件,显示结果:
git status
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: index.html
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: lib/simplegit.rb
现在想要切换分支,但是还不想要进行提交,运行git stash
或git stash save
:
git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
工作目录变干净了,并且刚刚的修改都不存在了:
git status
# On branch master nothing to commit, working directory clean
在这时,能够轻易地切换分支并在其他工作投入,此时修改将被存储在栈上, 想要查看栈存的东西,可以执行git stash list
:
git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
在本例中,有两个之前做的暂存,所以接触到了三个不同的暂存工作。 可以通过原来stash命令的帮助提示的命令将刚刚暂存的工作重新应用:git stash apply
。
如果想要应用其中一个更旧的暂存,可以通过名字指定它,比如:git stash apply stash@{2}
, 如果不指定一个暂存,Git认为指定的是最近的暂存:
git stash apply
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: index.html
# modified: lib/simplegit.rb #
可以看到Git重新修改了当您暂存时撤消的文件。 也可以运行git stash pop
来应用暂存并从栈上扔掉它。
暂存的丢弃可以运行git stash drop
加上将要移除的暂存的名字来移除它:
git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
从暂存创建一个分支
如果暂存了一些工作,在后续重新应用工作时可能会有问题。 如果应用尝试修改刚刚修改的文件,您会得到一个合并冲突并不得不解决它。 如果想要一个轻松的方式来再次测试储藏的改动,可以运行git stash branch
创建一个新分支,检出暂存工作时所在的提交,重新在那应用工作,然后在应用成功后扔掉:
git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: index.html
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# modified: lib/simplegit.rb # Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
这是在新分支轻松恢复暂存工作并继续工作的一个很不错的途径。
修改代码历史
Git的强大之处在于它允许您随时调整提交历史。无论是调整顺序、修改信息、编辑文件,还是合并、拆分、删除提交,都可以在工作前轻松完成。
修改最后一次提交
最常见的操作是修改最近一次提交,您可能想更改提交信息或更新文件。
如果,只是想修改最近一次提交的提交信息,那么很简单:
git commit --amend
想要精简提交信息或修改已提交的快照,只需进入文本编辑器修改最近一条提交信息,然后保存关闭即可。若已提交却忘记添加文件,可通过
git add
或git rm
修改文件,再运行git commit --amend
更新快照,但请注意,修正会改变提交的SHA-1校验和,类似小变基,推送后请勿修正。修改多个提交信息
要修改历史中较早的提交,需使用更复杂的工具。Git无直接改变历史工具,但可用交互式变基。通过
git rebase -i
,可在任意提交后停止,修改信息、添加文件等。要修改最后三次提交,使用HEAD~3
作为参数传递给git rebase -i
命令。记住,这实际上指定了以前的四次提交中的父提交。git rebase -i HEAD~3
需要重点注意的是相对于正常使用的 log 命令,这些提交显示的顺序是相反的。 运行一次 log 命令,会看到类似这样的东西:
git log --pretty=format:"%h %s" HEAD~3..HEAD a5f4a0d added cat-file 310154e updated README formatting and added blame f7f3f6d changed my name a bit
反序变基脚本, 它从指定提交(如HEAD~3)逆序重演每个变更,要停在某次变更上修改,编辑脚本,将想改的‘pick’换成‘edit’。
例如,只调第三次提交
edit f7f3f6d changed my name a bit pick 310154e updated README formatting and added blame pick a5f4a0d added cat-file
当保存并退出编辑器时,Git将您带回到列表中的最后一次提交,把送回命令行并提示以下信息:
git rebase -i HEAD~3 Stopped at f7f3f6d... changed my name a bit You can amend the commit now, with git commit --amend Once you’re satisfied with your changes, run git rebase --continue
这些指令准确地告诉您该做什么。
git commit --amend
修改提交信息,然后退出编辑器。 然后,运行
git rebase --continue
这个命令将会自动地应用另外两个提交,然后就完成了。 如果需要将不止一处的 pick 改为 edit,需要在每一个修改为 edit 的提交上重复这些步骤。 每一次,Git 将会停止,让您修正提交,然后继续直到完成。
想重塑您的提交历史,可以通过变基命令操作,但需注意,此操作针对的是
HEAD~3..HEAD
范围内的提交,且会彻底重写它们,关键要点如下:重写提交:变基不仅修改内容,还重写提交信息。
避免冲突:别碰已推送的提交,否则会造成版本混乱。
编辑器操作:运行命令后,文本编辑器将展示待重写的提交列表。
pick f7f3f6d changed my name a bit # 使用这个提交。 pick 310154e updated README formatting and added blame pick a5f4a0d added cat-file # Rebase 710f0f8..a5f4a0d onto 710f0f8 # # 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 # # 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
重新排序提交
也可以使用交互式变基来重新排序或完全移除提交。 如果想要移除 “
added cat-file
” 提交然后修改另外两个提交引入的顺序,可以将变基脚本从这样:pick f7f3f6d changed my name a bit pick 310154e updated README formatting and added blame pick a5f4a0d added cat-file
改为这样:
pick 310154e updated README formatting and added blame pick f7f3f6d changed my name a bit
当保存并退出编辑器时,Git 将您的分支带回这些提交的父提交,应用 310154e,然后应用 f7f3f6d,最后停止。 事实修改了那些提交的顺序并完全地移除了 “
added cat-file
” 提交。压缩提交
通过交互式变基工具,也可以将一连串提交压缩成一个单独的提交。 在变基信息中脚本给出了有用的指令。
# 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 # # 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
如果,指定 “squash” 而不是 “pick” 或 “edit”,Git将应用两者的修改并合并提交信息在一起。 所以,如果想要这三次提交变为一个提交,可以这样修改脚本。
pick f7f3f6d changed my name a bit squash 310154e updated README formatting and added blame squash a5f4a0d added cat-file
当保存并退出编辑器时,Git 应用所有的三次修改然后将你放到编辑器中来合并三次提交信息。
# This is a combination of 3 commits. # The first commit's message is: changed my name a bit # This is the 2nd commit message: updated README formatting and added blame # This is the 3rd commit message: added cat-file
当你保存之后,你就拥有了一个包含前三次提交的全部变更的提交。
拆分提交
拆分一个提交会撤消这个提交,然后多次地部分地暂存与提交直到完成你所需次数的提交。 例如,假设想要拆分三次提交的中间那次提交。 想要将它拆分为两次提交:第一个 “
updated README formatting
”,第二个 “added blame
” 来代替原来的 “updated README formatting and added blame
”。 可以通过修改rebase -i
的脚本来做到这点,将要拆分的提交的指令修改为 “edit”。pick f7f3f6d changed my name a bit edit 310154e updated README formatting and added blame pick a5f4a0d added cat-file
然后,当脚本将你进入到命令行时,重置那个提交,拿到被重置的修改,从中创建几次提交。 当保存并退出编辑器时,Git带您到列表中第一个提交的父提交,应用第一个提交(f7f3f6d),应用第二个提交(310154e),然后让你进入命令行。 那里,可以通过
git reset HEAD^
做一次针对那个提交的混合重置,实际上将会撤消那次提交并将修改的文件未暂存。 现在可以暂存并提交文件直到有几个提交,然后当完成时运行git rebase --continue
:git reset HEAD^ git add README git commit -m 'updated README formatting' git add lib/simplegit.rb git commit -m 'added blame' git rebase --continue
Git在脚本中应用最后一次提交(a5f4a0d),历史记录看起来像这样:
git log -4 --pretty=format:"%h %s" 1c002dd added cat-file 9b29157 added blame 35cfb2b updated README formatting f3cc40e changed my name a bit
再次强调,如果您正打算推送提交到共享仓库,请先暂停。我们有一个重要更新:所有在列表中的提交的SHA-1校验和已经更改。为确保数据的完整性和避免冲突,请务必确认这些提交尚未被推送到共享仓库。