本文共 6206 字,大约阅读时间需要 20 分钟。
使用 Git 进行版本管理时,肯定不只做提交,有时候也会需要回退修改,并且在回退的基础上进行重新提交,这时候有几个常用的命令就需要用到了,下面分别做介绍。
首先,我们查看当前提交记录的命令:
$ git logcommit bfee9d6618bc1deae52ac4a7942b96990bbfe661 (HEAD -> master, origin/master, origin/HEAD)Author: sylan215Date: Thu Oct 19 15:19:30 2017 +0800 dddcommit fbb28efb4e156031704abbf015b12c8ef16031c8Author: sylan215 Date: Thu Oct 19 15:15:26 2017 +0800 revert
如果 log 太多,可以加上参数 --pretty=oneline
使用:
$ git log --pretty=onelinebfee9d6618bc1deae52ac4a7942b96990bbfe661 (HEAD -> master, origin/master, origin/HEAD) dddfbb28efb4e156031704abbf015b12c8ef16031c8 revertca0e36b485a3de75e6e11064aecc22ce100652dd new line45dcf1bc797a773ca3dee07fc795ef986d10c346 t5e29356aa7aea31e7e6bce302abbc2259324d806 test
查看本机命令的执行记录:
$ git reflogbfee9d6 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to bfee9d6618bc1deae52ac4a7942b96990bbfe661bfee9d6 (HEAD -> master, origin/master, origin/HEAD) HEAD@{1}: commit: dddfbb28ef HEAD@{2}: reset: moving to fbb28efb4e156031704abbf015b12c8ef16031c8fbb28ef HEAD@{3}: reset: moving to fbb28efb4e156031704abbf015b12c8ef16031c8fbb28ef HEAD@{4}: commit: revertca0e36b HEAD@{5}: reset: moving to ca0e36b485a3de75e6e11064aecc22ce100652ddca0e36b HEAD@{6}: commit: new line45dcf1b HEAD@{7}: reset: moving to 45dcf1
我们可以通过上述两种方式查看之前的记录,并找到要回退的版本,回退的版本有两种表示方法,一个是 commit id,就是那一串字符,一种是相对 HEAD 的序号,看下命令:
$ git reset --hard HEAD^^HEAD is now at ca0e36b new line$ git reset --har bfee9dHEAD is now at bfee9d6 ddd
我们先使用 HEAD^^
回退了两个版本,然后又使用 bfee9d
这个 commit id 回到了最新版本,注意 HEAD
方式只能回退到旧版本,没法往新版本前进, commit id 的方式可以回退到任意有效 id 的版本,至于怎么查看版本对应的 id 请看最开始介绍的 git log
和 git reflog
命令。
这个命令我们还可变相达成丢弃目前所有修改的效果,直接运行
git reset --hard HEAD
就行。
回退版本后,我们重新进行修改,并提交,会发现有如下报错:
$ git add .$ git commit -am "test reset"[master 88b1dc8] test reset 1 file changed, 1 insertion(+), 1 deletion(-)$ git pushTo 192.168.252.130:/srv/myfiles.git ! [rejected] master -> master (non-fast-forward)error: failed to push some refs to 'git@192.168.252.130:/srv/myfiles.git'hint: Updates were rejected because the tip of your current branch is behindhint: its remote counterpart. Integrate the remote changes (e.g.hint: 'git pull ...') before pushing again.hint: See the 'Note about fast-forwards' in 'git push --help' for details.
解决方法是使用命令 git push -f
解决:
$ git push -fCounting objects: 3, done.Compressing objects: 100% (2/2), done.Writing objects: 100% (3/3), 286 bytes | 286.00 KiB/s, done.Total 3 (delta 0), reused 0 (delta 0)To 192.168.252.130:/srv/myfiles.git + bfee9d6...88b1dc8 master -> master (forced update)
注意:git push -f
是强制提交的意思,如果和 reset 结合使用,就会把最新版本到 reset 到的版本之间的所有 commit 全部抹掉了,这在多人协作时,要特别注意。
具体我们通过命令后 git long --pretty=oneline
看得更直观:
$ git log --pretty=oneline88b1dc8cb7228f7d1fe14d510a62201a9d584118 (HEAD -> master, origin/master, origin/HEAD) test resetca0e36b485a3de75e6e11064aecc22ce100652dd new line45dcf1bc797a773ca3dee07fc795ef986d10c346 t5e29356aa7aea31e7e6bce302abbc2259324d806 test
和最上面那一次的输出对比,commit id ca0e36b485a3de75e6e11064aecc22ce100652dd 之后的两个提交 id 都被回退了(fbb28efb4e156031704abbf015b12c8ef16031c8 和 bfee9d6618bc1deae52ac4a7942b96990bbfe661)。
使用 reset 是直接抹杀掉 commit 的方式,另外还有一种真正的「回退」命令,就是 revert,它的效果时,在当前版本基础上,删掉要回退版本的修改内容后新建一次提交。
我们看看效果:$ git log --pretty=oneline9eecd39b8e6a2109c3678c42dc034db2190840f6 (HEAD -> master, origin/master, origin/HEAD) changee4f5e6920c22b748d765824e0be21015332fafa4 init$ git revert 9eec[master f7c9eb4] Revert "change" 1 file changed, 1 insertion(+), 2 deletions(-)$ git log --pretty=onelinef7c9eb4120d368915a6e5491bf85dc5cd87a424f (HEAD -> master) Revert "change"9eecd39b8e6a2109c3678c42dc034db2190840f6 (origin/master, origin/HEAD) changee4f5e6920c22b748d765824e0be21015332fafa4 init
我们在最新版本的基础上,把最后一次提交的修改给回退了,同时用回退后版本生成了一次提交,并生成了新的 commit id,这样所有的操作 log 均得到了正确的保留。
注意:命令 revert 是指回退指定版本的修改内容,而不是指指定版本到当前版本的所有内容,所以如果给定的 commit id 不是当前版本的最新 commit id,那么就会报错:
$ git log --pretty=oneline45734f3dc12f45e78504bd0fb52ba334c0ae2c9f (HEAD -> master, origin/master, origin/HEAD) test7c82b777a40dfb24fc1bba404be0daa3b3923a95 test revertf7c9eb4120d368915a6e5491bf85dc5cd87a424f Revert "change"9eecd39b8e6a2109c3678c42dc034db2190840f6 changee4f5e6920c22b748d765824e0be21015332fafa4 init$ git revert 7c82berror: could not revert 7c82b77... test reverthint: after resolving the conflicts, mark the corrected pathshint: with 'git add' or 'git rm 'hint: and commit the result with 'git commit'$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.You are currently reverting commit 7c82b77. (fix conflicts and run "git revert --continue") (use "git revert --abort" to cancel the revert operation)Unmerged paths: (use "git reset HEAD ..." to unstage) (use "git add ..." to mark resolution) both modified: test2.txtno changes added to commit (use "git add" and/or "git commit -a")
如果上图,我们跳过了 45734 的修改,想只回退 7c82b 的修改,这时候就提示冲突了,这时候要么手工修改冲突,要么取消 revert 后,一次指定多个 revert id 来实现,下面是一次使用多个 revert id 进行实现:
$ git revert --abort$ git log --pretty=oneline45734f3dc12f45e78504bd0fb52ba334c0ae2c9f (HEAD -> master, origin/master, origin/HEAD) test7c82b777a40dfb24fc1bba404be0daa3b3923a95 test revertf7c9eb4120d368915a6e5491bf85dc5cd87a424f Revert "change"9eecd39b8e6a2109c3678c42dc034db2190840f6 changee4f5e6920c22b748d765824e0be21015332fafa4 init$ git revert 45734 7c82b[master 8140eb0] Revert "test" 1 file changed, 1 insertion(+), 3 deletions(-)[master 191816d] Revert "test revert" 1 file changed, 1 insertion(+), 2 deletions(-)$ git log --pretty=oneline191816d84c02a4ba591d3739739ddd0df114d7f1 (HEAD -> master) Revert "test revert"8140eb0f69493f1a6306b0e92822f07c049a7a50 Revert "test"45734f3dc12f45e78504bd0fb52ba334c0ae2c9f (origin/master, origin/HEAD) test7c82b777a40dfb24fc1bba404be0daa3b3923a95 test revertf7c9eb4120d368915a6e5491bf85dc5cd87a424f Revert "change"9eecd39b8e6a2109c3678c42dc034db2190840f6 changee4f5e6920c22b748d765824e0be21015332fafa4 init
这时候如果我们查看文件,会发现 45734 和 7c82b 的内容都被回退了,并新生成了两次的 commit(每个 commit id 的回退会单独生成一条记录)。
特别说明一下,为了保证 revert 的效果,建议每次提交修改的时候,尽量减少非耦合文件的一起提交,分批提交可以更利于以后的 revert。
转载于:https://blog.51cto.com/sylan215/2165155