大家好,我是小富~

技术交换关注公众号:程序员内点事

传送门:原文地址

git对于大家应该都不太生疏,纯熟应用git曾经成为程序员的一项基本技能,只管在工作中有诸如 Sourcetree这样牛X的客户端工具,使得合并代码变的很不便。但找工作面试和一些需彰显集体实力的场景,依然须要咱们把握足够多的git命令。

下边咱们整顿了45个日常用git合代码的经典操作场景,根本笼罩了工作中的需要。

我方才提交了什么?

如果你用 git commit -a 提交了一次变动(changes),而你又不确定到底这次提交了哪些内容。 你就能够用上面的命令显示以后HEAD上的最近一次的提交(commit):

(main)$ git show

或者

$ git log -n1 -p

我的提交信息(commit message)写错了

如果你的提交信息(commit message)写错了且这次提交(commit)还没有推(push), 你能够通过上面的办法来批改提交信息(commit message):

$ git commit --amend --only

这会关上你的默认编辑器, 在这里你能够编辑信息. 另一方面, 你也能够用一条命令一次实现:

$ git commit --amend --only -m 'xxxxxxx'

如果你曾经推(push)了这次提交(commit), 你能够批改这次提交(commit)而后强推(force push), 然而不举荐这么做。

我提交(commit)里的用户名和邮箱不对

如果这只是单个提交(commit),批改它:

$ git commit --amend --author "New Authorname <authoremail@mydomain.com>"

如果你须要批改所有历史, 参考 'git filter-branch'的指南页.

我想从一个提交(commit)里移除一个文件

通过上面的办法,从一个提交(commit)里移除一个文件:

$ git checkout HEAD^ myfile$ git add -A$ git commit --amend

这将十分有用,当你有一个凋谢的补丁(open patch),你往上面提交了一个不必要的文件,你须要强推(force push)去更新这个近程补丁。

我想删除我的的最初一次提交(commit)

如果你须要删除推了的提交(pushed commits),你能够应用上面的办法。可是,这会不可逆的扭转你的历史,也会搞乱那些曾经从该仓库拉取(pulled)了的人的历史。简而言之,如果你不是很确定,千万不要这么做。

$ git reset HEAD^ --hard$ git push -f [remote] [branch]

如果你还没有推到近程, 把Git重置(reset)到你最初一次提交前的状态就能够了(同时保留暂存的变动):

(my-branch*)$ git reset --soft HEAD@{1}

这只能在没有推送之前有用. 如果你曾经推了, 惟一平安能做的是 git revert SHAofBadCommit, 那会创立一个新的提交(commit)用于吊销前一个提交的所有变动(changes); 或者, 如果你推的这个分支是rebase-safe的 (例如: 其它开发者不会从这个分支拉), 只须要应用 git push -f

删除任意提交(commit)

同样的正告:不到万不得已的时候不要这么做.

$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT$ git push -f [remote] [branch]

或者做一个 交互式rebase 删除那些你想要删除的提交(commit)里所对应的行。

我尝试推一个修改后的提交(amended commit)到近程,然而报错:

To https://github.com/yourusername/repo.git! [rejected]        mybranch -> mybranch (non-fast-forward)error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.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.

留神, rebasing(见上面)和修改(amending)会用一个新的提交(commit)代替旧的, 所以如果之前你曾经往近程仓库上推过一次修改前的提交(commit),那你当初就必须强推(force push) (-f)。 留神 – 总是 确保你指明一个分支!

(my-branch)$ git push origin mybranch -f

一般来说, 要防止强推. 最好是创立和推(push)一个新的提交(commit),而不是强推一个修改后的提交。后者会使那些与该分支或该分支的子分支工作的开发者,在源历史中产生抵触。

我意外的做了一次硬重置(hard reset),我想找回我的内容

如果你意外的做了 git reset --hard, 你通常能找回你的提交(commit), 因为Git对每件事都会有日志,且都会保留几天。

(main)$ git reflog

你将会看到一个你过来提交(commit)的列表, 和一个重置的提交。 抉择你想要回到的提交(commit)的SHA,再重置一次:

(main)$ git reset --hard SHA1234

这样就实现了。

暂存(Staging)

我须要把暂存的内容增加到上一次的提交(commit)

(my-branch*)$ git commit --amend

我想要暂存一个新文件的一部分,而不是这个文件的全副

一般来说, 如果你想暂存一个文件的一部分, 你可这样做:

$ git add --patch filename.x

-p 简写。这会关上交互模式, 你将可能用 s 选项来分隔提交(commit); 然而, 如果这个文件是新的, 会没有这个抉择, 增加一个新文件时, 这样做:

$ git add -N filename.x

而后, 你须要用 e 选项来手动抉择须要增加的行,执行 git diff --cached 将会显示哪些行暂存了哪些行只是保留在本地了。

我想把在一个文件里的变动(changes)加到两个提交(commit)里

git add 会把整个文件退出到一个提交. git add -p 容许交互式的抉择你想要提交的局部.

我想把暂存的内容变成未暂存,把未暂存的内容暂存起来

少数状况下,你应该将所有的内容变为未暂存,而后再抉择你想要的内容进行commit。
但假设你就是想要这么做,这里你能够创立一个长期的commit来保留你已暂存的内容,而后暂存你的未暂存的内容并进行stash。而后reset最初一个commit将本来暂存的内容变为未暂存,最初stash pop回来。

$ git commit -m "WIP"$ git add .$ git stash$ git reset HEAD^$ git stash pop --index 0

留神1: 这里应用pop仅仅是因为想尽可能放弃幂等。
留神2: 如果你不加上--index你会把暂存的文件标记为为存储。

未暂存(Unstaged)的内容

我想把未暂存的内容挪动到一个新分支

$ git checkout -b my-branch

我想把未暂存的内容挪动到另一个已存在的分支

$ git stash$ git checkout my-branch$ git stash pop

我想抛弃本地未提交的变动(uncommitted changes)

如果你只是想重置源(origin)和你本地(local)之间的一些提交(commit),你能够:

# one commit(my-branch)$ git reset --hard HEAD^# two commits(my-branch)$ git reset --hard HEAD^^# four commits(my-branch)$ git reset --hard HEAD~4# or(main)$ git checkout -f

重置某个非凡的文件, 你能够用文件名做为参数:

$ git reset filename

我想抛弃某些未暂存的内容

如果你想抛弃工作拷贝中的一部分内容,而不是全副。

签出(checkout)不须要的内容,保留须要的。

$ git checkout -p# Answer y to all of the snippets you want to drop

另外一个办法是应用 stash, Stash所有要保留下的内容, 重置工作拷贝, 从新利用保留的局部。

$ git stash -p# Select all of the snippets you want to save$ git reset --hard$ git stash pop

或者, stash 你不须要的局部, 而后stash drop。

$ git stash -p# Select all of the snippets you don't want to save$ git stash drop

分支(Branches)

我从谬误的分支拉取了内容,或把内容拉取到了谬误的分支

这是另外一种应用 git reflog 状况,找到在这次谬误拉(pull) 之前HEAD的指向。

(main)$ git reflogab7555f HEAD@{0}: pull origin wrong-branch: Fast-forwardc5bc55a HEAD@{1}: checkout: checkout message goes here

重置分支到你所需的提交(desired commit):

$ git reset --hard c5bc55a

实现。

我想扔掉本地的提交(commit),以便我的分支与近程的保持一致

先确认你没有推(push)你的内容到近程。

git status 会显示你当先(ahead)源(origin)多少个提交:

(my-branch)$ git status# On branch my-branch# Your branch is ahead of 'origin/my-branch' by 2 commits.#   (use "git push" to publish your local commits)#

一种办法是:

(main)$ git reset --hard origin/my-branch

我须要提交到一个新分支,但谬误的提交到了main

在main下创立一个新分支,不切换到新分支,仍在main下:

(main)$ git branch my-branch

把main分支重置到前一个提交:

(main)$ git reset --hard HEAD^

HEAD^HEAD^1 的简写,你能够通过指定要设置的HEAD来进一步重置。

或者, 如果你不想应用 HEAD^, 找到你想重置到的提交(commit)的hash(git log 可能实现), 而后重置到这个hash。 应用git push 同步内容到近程。

例如, main分支想重置到的提交的hash为a13b85e:

(main)$ git reset --hard a13b85eHEAD is now at a13b85e

签出(checkout)方才新建的分支持续工作:

(main)$ git checkout my-branch

我想保留来自另外一个ref-ish的整个文件

假如你正在做一个原型计划(原文为working spike (see note)), 有成百的内容,每个都工作得很好。当初, 你提交到了一个分支,保留工作内容:

(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."

当你想要把它放到一个分支里 (可能是feature, 或者 develop), 你关怀是放弃整个文件的残缺,你想要一个大的提交分隔成比拟小。

假如你有:

  • 分支 solution, 领有原型计划, 当先 develop 分支。
  • 分支 develop, 在这里你利用原型计划的一些内容。

我去能够通过把内容拿到你的分支里,来解决这个问题:

(develop)$ git checkout solution -- file1.txt

这会把这个文件内容从分支 solution 拿到分支 develop 里来:

# On branch develop# Your branch is up-to-date with 'origin/develop'.# Changes to be committed:#  (use "git reset HEAD <file>..." to unstage)##        modified:   file1.txt

而后, 失常提交。

Note: Spike solutions are made to analyze or solve the problem. These solutions are used for estimation and discarded once everyone gets clear visualization of the problem.

我把几个提交(commit)提交到了同一个分支,而这些提交应该散布在不同的分支里

假如你有一个main分支, 执行git log, 你看到你做过两次提交:

(main)$ git logcommit e3851e817c451cc36f2e6f3049db528415e3c114Author: Alex Lee <alexlee@example.com>Date:   Tue Jul 22 15:39:27 2014 -0400    Bug #21 - Added CSRF protectioncommit 5ea51731d150f7ddc4a365437931cd8be3bf3131Author: Alex Lee <alexlee@example.com>Date:   Tue Jul 22 15:39:12 2014 -0400    Bug #14 - Fixed spacing on titlecommit a13b85e984171c6e2a1729bb061994525f626d14Author: Aki Rose <akirose@example.com>Date:   Tue Jul 21 01:12:48 2014 -0400    First commit

让咱们用提交hash(commit hash)标记bug (e3851e8 for #21, 5ea5173 for #14).

首先, 咱们把main分支重置到正确的提交(a13b85e):

(main)$ git reset --hard a13b85eHEAD is now at a13b85e

当初, 咱们对 bug #21 创立一个新的分支:

(main)$ git checkout -b 21(21)$

接着, 咱们用 cherry-pick 把对bug #21的提交放入以后分支。 这意味着咱们将利用(apply)这个提交(commit),仅仅这一个提交(commit),间接在HEAD下面。

(21)$ git cherry-pick e3851e8

这时候, 这里可能会产生抵触, 参见交互式 rebasing 章 抵触节 解决抵触.

再者, 咱们为bug #14 创立一个新的分支, 也基于main分支

(21)$ git checkout main(main)$ git checkout -b 14(14)$

最初, 为 bug #14 执行 cherry-pick:

(14)$ git cherry-pick 5ea5173

我想删除上游(upstream)分支被删除了的本地分支

一旦你在github 下面合并(merge)了一个pull request, 你就能够删除你fork里被合并的分支。 如果你不筹备持续在这个分支里工作, 删除这个分支的本地拷贝会更洁净,使你不会陷入工作分支和一堆古老分支的凌乱之中。

$ git fetch -p

我不小心删除了我的分支

如果你定期推送到近程, 少数状况下应该是平安的,但有些时候还是可能删除了还没有推到近程的分支。 让咱们先创立一个分支和一个新的文件:

(main)$ git checkout -b my-branch(my-branch)$ git branch(my-branch)$ touch foo.txt(my-branch)$ lsREADME.md foo.txt

增加文件并做一次提交

(my-branch)$ git add .(my-branch)$ git commit -m 'foo.txt added'(my-branch)$ foo.txt added 1 files changed, 1 insertions(+) create mode 100644 foo.txt(my-branch)$ git logcommit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012Author: siemiatj <siemiatj@example.com>Date:   Wed Jul 30 00:34:10 2014 +0200    foo.txt addedcommit 69204cdf0acbab201619d95ad8295928e7f411d5Author: Kate Hudson <katehudson@example.com>Date:   Tue Jul 29 13:14:46 2014 -0400    Fixes #6: Force pushing after amending commits

当初咱们切回到主(main)分支,‘不小心的’删除my-branch分支

(my-branch)$ git checkout mainSwitched to branch 'main'Your branch is up-to-date with 'origin/main'.(main)$ git branch -D my-branchDeleted branch my-branch (was 4e3cd85).(main)$ echo oh noes, deleted my branch!oh noes, deleted my branch!

在这时候你应该想起了reflog, 一个升级版的日志,它存储了仓库(repo)外面所有动作的历史。

(main)$ git reflog69204cd HEAD@{0}: checkout: moving from my-branch to main4e3cd85 HEAD@{1}: commit: foo.txt added69204cd HEAD@{2}: checkout: moving from main to my-branch

正如你所见,咱们有一个来自删除分支的提交hash(commit hash),接下来看看是否能复原删除了的分支。

(main)$ git checkout -b my-branch-helpSwitched to a new branch 'my-branch-help'(my-branch-help)$ git reset --hard 4e3cd85HEAD is now at 4e3cd85 foo.txt added(my-branch-help)$ lsREADME.md foo.txt

看! 咱们把删除的文件找回来了。 Git的 reflog 在rebasing出错的时候也是同样有用的。

我想删除一个分支

删除一个近程分支:

(main)$ git push origin --delete my-branch

你也能够:

(main)$ git push origin :my-branch

删除一个本地分支:

(main)$ git branch -D my-branch

我想从他人正在工作的近程分支签出(checkout)一个分支

首先, 从近程拉取(fetch) 所有分支:

(main)$ git fetch --all

假如你想要从近程的daves分支签出到本地的daves

(main)$ git checkout --track origin/davesBranch daves set up to track remote branch daves from origin.Switched to a new branch 'daves'

(--trackgit checkout -b [branch] [remotename]/[branch] 的简写)

这样就失去了一个daves分支的本地拷贝, 任何推过(pushed)的更新,近程都能看到.

Rebasing 和合并(Merging)

我想撤销rebase/merge

你能够合并(merge)或rebase了一个谬误的分支, 或者实现不了一个进行中的rebase/merge。 Git 在进行危险操作的时候会把原始的HEAD保留在一个叫ORIG_HEAD的变量里, 所以要把分支复原到rebase/merge前的状态是很容易的。

(my-branch)$ git reset --hard ORIG_HEAD

我曾经rebase过, 然而我不想强推(force push)

可怜的是,如果你想把这些变动(changes)反馈到近程分支上,你就必须得强推(force push)。 是因你快进(Fast forward)了提交,扭转了Git历史, 近程分支不会承受变动(changes),除非强推(force push)。这就是许多人应用 merge 工作流, 而不是 rebasing 工作流的次要起因之一, 开发者的强推(force push)会使大的团队陷入麻烦。应用时须要留神,一种平安应用 rebase 的办法是,不要把你的变动(changes)反映到近程分支上, 而是按上面的做:

(main)$ git checkout my-branch(my-branch)$ git rebase -i main(my-branch)$ git checkout main(main)$ git merge --ff-only my-branch

我须要组合(combine)几个提交(commit)

假如你的工作分支将会做对于 main 的pull-request。 个别状况下你不关怀提交(commit)的工夫戳,只想组合 所有 提交(commit) 到一个独自的外面, 而后重置(reset)重提交(recommit)。 确保主(main)分支是最新的和你的变动都曾经提交了, 而后:

(my-branch)$ git reset --soft main(my-branch)$ git commit -am "New awesome feature"

如果你想要更多的管制, 想要保留工夫戳, 你须要做交互式rebase (interactive rebase):

(my-branch)$ git rebase -i main

如果没有绝对的其它分支, 你将不得不绝对本人的HEAD 进行 rebase。 例如:你想组合最近的两次提交(commit), 你将绝对于HEAD~2 进行rebase, 组合最近3次提交(commit), 绝对于HEAD~3, 等等。

(main)$ git rebase -i HEAD~2

在你执行了交互式 rebase的命令(interactive rebase command)后, 你将在你的编辑器里看到相似上面的内容:

pick a9c8a1d Some refactoringpick 01b2fd8 New awesome featurepick b729ad5 fixuppick e3851e8 another fix# Rebase 8074d12..b729ad5 onto 8074d12## 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

所有以 # 结尾的行都是正文, 不会影响 rebase.

而后,你能够用任何下面命令列表的命令替换 pick, 你也能够通过删除对应的行来删除一个提交(commit)。

例如, 如果你想 独自保留最旧(first)的提交(commit),组合所有剩下的到第二个外面, 你就应该编辑第二个提交(commit)前面的每个提交(commit) 前的单词为 f:

pick a9c8a1d Some refactoringpick 01b2fd8 New awesome featuref b729ad5 fixupf e3851e8 another fix

如果你想组合这些提交(commit) 并重命名这个提交(commit), 你应该在第二个提交(commit)旁边增加一个r,或者更简略的用s 代替 f:

pick a9c8a1d Some refactoringpick 01b2fd8 New awesome features b729ad5 fixups e3851e8 another fix

你能够在接下来弹出的文本提示框里重命名提交(commit)。

Newer, awesomer features# Please enter the commit message for your changes. Lines starting# with '#' will be ignored, and an empty message aborts the commit.# rebase in progress; onto 8074d12# You are currently editing a commit while rebasing branch 'main' on '8074d12'.## Changes to be committed:#    modified:   README.md#

如果胜利了, 你应该看到相似上面的内容:

(main)$ Successfully rebased and updated refs/heads/main.

平安合并(merging)策略

--no-commit 执行合并(merge)但不主动提交, 给用户在做提交前检查和批改的机会。 no-ff 会为个性分支(feature branch)的存在过留下证据, 放弃我的项目历史统一。

(main)$ git merge --no-ff --no-commit my-branch

我须要将一个分支合并成一个提交(commit)

(main)$ git merge --squash my-branch

我只想组合(combine)未推的提交(unpushed commit)

有时候,在将数据推向上游之前,你有几个正在进行的工作提交(commit)。这时候不心愿把曾经推(push)过的组合进来,因为其他人可能曾经有提交(commit)援用它们了。

(main)$ git rebase -i @{u}

这会产生一次交互式的rebase(interactive rebase), 只会列出没有推(push)的提交(commit), 在这个列表时进行reorder/fix/squash 都是平安的。

查看是否分支上的所有提交(commit)都合并(merge)过了

查看一个分支上的所有提交(commit)是否都曾经合并(merge)到了其它分支, 你应该在这些分支的head(或任何 commits)之间做一次diff:

(main)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll

这会通知你在一个分支里有而另一个分支没有的所有提交(commit), 和分支之间不共享的提交(commit)的列表。 另一个做法能够是:

(main)$ git log main ^feature/120-on-scroll --no-merges

交互式rebase(interactive rebase)可能呈现的问题

这个rebase 编辑屏幕呈现'noop'

如果你看到的是这样:

noop

这意味着你rebase的分支和以后分支在同一个提交(commit)上, 或者 当先(ahead) 以后分支。 你能够尝试:

  • 查看确保主(main)分支没有问题
  • rebase HEAD~2 或者更早

有抵触的状况

如果你不能胜利的实现rebase, 你可能必须要解决抵触。

首先执行 git status 找出哪些文件有抵触:

(my-branch)$ git statusOn branch my-branchChanges 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:   README.md

在这个例子外面, README.md 有抵触。 关上这个文件找到相似上面的内容:

   <<<<<<< HEAD   some code   =========   some code   >>>>>>> new-commit

你须要解决新提交的代码(示例里, 从两头==线到new-commit的中央)与HEAD 之间不一样的中央.

有时候这些合并非常复杂,你应该应用可视化的差别编辑器(visual diff editor):

(main*)$ git mergetool -t opendiff

在你解决完所有抵触和测试过后, git add 变动了的(changed)文件, 而后用git rebase --continue 持续rebase。

(my-branch)$ git add README.md(my-branch)$ git rebase --continue

如果在解决完所有的抵触过后,失去了与提交前一样的后果, 能够执行git rebase --skip

任何时候你想完结整个rebase 过程,回来rebase前的分支状态, 你能够做:

(my-branch)$ git rebase --abort

Stash

暂存所有改变

暂存你工作目录下的所有改变

$ git stash

你能够应用-u来排除一些文件

$ git stash -u

暂存指定文件

假如你只想暂存某一个文件

$ git stash push working-directory-path/filename.ext

假如你想暂存多个文件

$ git stash push working-directory-path/filename1.ext working-directory-path/filename2.ext

暂存时记录音讯

这样你能够在list时看到它

$ git stash save <message>

$ git stash push -m <message>

应用某个指定暂存

首先你能够查看你的stash记录

$ git stash list

而后你能够apply某个stash

$ git stash apply "stash@{n}"

此处, 'n'是stash在栈中的地位,最上层的stash会是0

除此之外,也能够应用工夫标记(如果你能记得的话)。

$ git stash apply "stash@{2.hours.ago}"

暂存时保留未暂存的内容

你须要手动create一个stash commit, 而后应用git stash store

$ git stash create$ git stash store -m "commit-message" CREATED_SHA1

杂项(Miscellaneous Objects)

克隆所有子模块

$ git clone --recursive git://github.com/foo/bar.git

如果曾经克隆了:

$ git submodule update --init --recursive

删除标签(tag)

$ git tag -d <tag_name>$ git push <remote> :refs/tags/<tag_name>

复原已删除标签(tag)

如果你想复原一个已删除标签(tag), 能够依照上面的步骤: 首先, 须要找到无法访问的标签(unreachable tag):

$ git fsck --unreachable | grep tag

记下这个标签(tag)的hash,而后用Git的 update-ref

$ git update-ref refs/tags/<tag_name> <hash>

这时你的标签(tag)应该曾经复原了。

已删除补丁(patch)

如果某人在 GitHub 上给你发了一个pull request, 然而而后他删除了他本人的原始 fork, 你将没法克隆他们的提交(commit)或应用 git am。在这种状况下, 最好手动的查看他们的提交(commit),并把它们拷贝到一个本地新分支,而后做提交。

做完提交后, 再批改作者,参见变更作者。 而后, 利用变动, 再发动一个新的pull request。

跟踪文件(Tracking Files)

我只想扭转一个文件名字的大小写,而不批改内容

(main)$ git mv --force myfile MyFile

我想从Git删除一个文件,但保留该文件

(main)$ git rm --cached log.txt

配置(Configuration)

我想给一些Git命令增加别名(alias)

在 OS X 和 Linux 下, 你的 Git的配置文件贮存在 ~/.gitconfig。我在[alias] 局部增加了一些快捷别名(和一些我容易拼写错误的),如下:

[alias]    a = add    amend = commit --amend    c = commit    ca = commit --amend    ci = commit -a    co = checkout    d = diff    dc = diff --changed    ds = diff --staged    f = fetch    loll = log --graph --decorate --pretty=oneline --abbrev-commit    m = merge    one = log --pretty=oneline    outstanding = rebase -i @{u}    s = status    unpushed = log @{u}    wc = whatchanged    wip = rebase -i @{u}    zap = fetch -p

我想缓存一个仓库(repository)的用户名和明码

你可能有一个仓库须要受权,这时你能够缓存用户名和明码,而不必每次推/拉(push/pull)的时候都输出,Credential helper能帮你。

$ git config --global credential.helper cache# Set git to use the credential memory cache
$ git config --global credential.helper 'cache --timeout=3600'# Set the cache to timeout after 1 hour (setting is in seconds)

我不晓得我做错了些什么

你把事件搞砸了:你 重置(reset) 了一些货色, 或者你合并了谬误的分支, 亦或你强推了后找不到你本人的提交(commit)了。有些时候, 你始终都做得很好, 但你想回到以前的某个状态。

这就是 git reflog 的目标, reflog 记录对分支顶端(the tip of a branch)的任何扭转, 即便那个顶端没有被任何分支或标签援用。基本上, 每次HEAD的扭转, 一条新的记录就会减少到reflog。遗憾的是,这只对本地分支起作用,且它只跟踪动作 (例如,不会跟踪一个没有被记录的文件的任何扭转)。

(main)$ git reflog0a2e358 HEAD@{0}: reset: moving to HEAD~20254ea7 HEAD@{1}: checkout: moving from 2.2 to mainc10f740 HEAD@{2}: checkout: moving from main to 2.2

下面的reflog展现了从main分支签出(checkout)到2.2 分支,而后再签回。 那里,还有一个硬重置(hard reset)到一个较旧的提交。最新的动作呈现在最下面以 HEAD@{0}标识.

如果事实证明你不小心回移(move back)了提交(commit), reflog 会蕴含你不小心回移前main上指向的提交(0254ea7)。

$ git reset --hard 0254ea7

而后应用git reset就能够把main改回到之前的commit,这提供了一个在历史被意外更改状况下的安全网。

技术交换关注公众号:程序员内点事

传送门:原文地址