aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenny Ballou <kballou@devnulllabs.io>2018-02-13 19:17:52 -0700
committerKenny Ballou <kballou@devnulllabs.io>2018-08-19 08:14:29 -0600
commit85f28f17be6545fd7b1f9f2c6dd9ffd86ed8bc84 (patch)
tree0c83f3f8198e8a76a3cd73beb345acddec345d76
parent6b16adec09389cfd4f707ed8cfbe1af18bbaf5f3 (diff)
downloadblog.kennyballou.com-85f28f17be6545fd7b1f9f2c6dd9ffd86ed8bc84.tar.gz
blog.kennyballou.com-85f28f17be6545fd7b1f9f2c6dd9ffd86ed8bc84.tar.xz
git-resurrecting-history post conversion
-rw-r--r--posts/git-resurrecting-history.org (renamed from content/blog/git-resurrecting-history.markdown)378
1 files changed, 230 insertions, 148 deletions
diff --git a/content/blog/git-resurrecting-history.markdown b/posts/git-resurrecting-history.org
index 9fb0123..6289fb8 100644
--- a/content/blog/git-resurrecting-history.markdown
+++ b/posts/git-resurrecting-history.org
@@ -1,35 +1,46 @@
----
-title: "Git: Resurrecting History"
-description: ""
-tags:
- - "Git"
- - "Tips and Tricks"
- - "How-to"
-date: "2016-09-14"
-categories:
- - "Development"
-slug: "git-resurrecting-history"
----
-
-We all make mistakes. They are inevitable. We must accept that we make them and
-move on. But making mistakes in Git seems to be overly complex to resolve and
-most will simply result to cloning anew and copying the working tree (or some
-subset) and moving on. This, to me, however, seems like a waste of bandwidth as
-most issues resulting in broken history are in fact quite easy to resolve,
-especially so once the necessary tools are known.
-
-## Git Reflog ##
-
-> Reference logs or "reflogs", record when the tips of branches and other
-> references were updated in the local repository.
---[`git-reflog(1)`][1]
+#+TITLE: Git Resurrecting History
+#+DESCRIPTION: Resurrect Lost History from the Information Manager from Hell
+#+TAGS: Git
+#+TAGS: Tips and Tricks
+#+TAGS: How-to
+#+DATE: 2016-09-04
+#+SLUG: git-resurrecting-history
+#+LINK: man-git-reflog https://www.kernel.org/pub/software/scm/git/docs/git-reflog.html
+#+LINK: git-scm-book-internals https://git-scm.com/book/en/v2/Git-Internals-Git-References
+#+LINK: man-git-fsck https://www.kernel.org/pub/software/scm/git/docs/git-fsck.html
+#+LINK: kb-git-in-reverse https://kennyballou.com/blog/2016/01/git-in-reverse/
+#+LINK: man-git-show https://www.kernel.org/pub/software/scm/git/docs/git-show.html
+#+LINK: man-git-cat-file https://www.kernel.org/pub/software/scm/git/docs/git-cat-file.html
+#+LINK: man-git-reset https://www.kernel.org/pub/software/scm/git/docs/git-reset.html
+#+LINK: man-git-rebase https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html
+#+LINK: xkcd-git https://xkcd.com/1597
+
+#+BEGIN_PREVIEW
+We all make mistakes. They are inevitable. We must accept that we make them
+and move on. But making mistakes in Git seems to be overly complex to resolve
+and most will simply result to cloning anew and copying the working tree (or
+some subset) and moving on. This, to me, however, seems like a waste of
+bandwidth as most issues resulting in broken history are in fact quite easy to
+resolve, especially so once the necessary tools are known.
+#+END_PREVIEW
+
+** Git Reflog
+ :PROPERTIES:
+ :CUSTOM_ID: git-reflog
+ :END:
+
+#+BEGIN_QUOTE
+ Reference logs or "reflogs", record when the tips of branches and other
+ references were updated in the local repository.
+ --[[man-git-reflog][~git-reflog(1)~]]
+#+END_QUOTE
That is, the reference log is the (meta)log of the actions against branches
-(tips) and other [references][2]. Every time we commit, merge, change branches,
-or perform _any_ action that might alter the commit a reference points to, this
-change is stored in the reflog of the current repository. For a freshly cloned
-repository, the reflog will be quite boring, e.g., a single entry for the
-initial clone.
+(tips) and other [[git-scm-book-internals][references]]. Every time we commit,
+merge, change branches, or perform /any/ action that might alter the commit a
+reference points to, this change is stored in the reflog of the current
+repository. For a freshly cloned repository, the reflog will be quite boring,
+e.g., a single entry for the initial clone.
However, after working on a project for a while, the reflog will have quite the
history of actions performed.
@@ -37,6 +48,7 @@ history of actions performed.
For example, here is the first 24 lines of the reflog for this blog's
repository:
+#+BEGIN_EXAMPLE
a1bbd00 HEAD@{0}: checkout: moving from master to git_resurrection
a1bbd00 HEAD@{1}: commit: Update paths of SSL certificate and key
d7fd8f8 HEAD@{2}: commit: Add all targets to phony
@@ -61,52 +73,62 @@ repository:
1a27df5 HEAD@{21}: checkout: moving from elixir_functional_fib to master
61f755b HEAD@{22}: commit: WIP: some post about fib
4137e6e HEAD@{23}: checkout: moving from master to elixir_functional_fib
+#+END_EXAMPLE
-The first column is the commit SHA-1 that is the _result_ of the action, the
+The first column is the commit SHA-1 that is the /result/ of the action, the
second column provides a shortcut reference that can be used anywhere a regular
-reference can be, the 3rd column is the action, e.g., `checkout`, `commit`,
-`merge`, etc., and a short description of the action. In the case of commits,
+reference can be, the 3rd column is the action, e.g., ~checkout~, ~commit~,
+~merge~, etc., and a short description of the action. In the case of commits,
the description text will be the summary line of the commit message.
From the reflog, we can see I've recently made a branch for this post, before
-that, I made several commits against the `master` branch, and before that, I
-performed a fast-forward merge of the local `elixir_releases` branch into the
-`master` branch. Etc.
+that, I made several commits against the ~master~ branch, and before that, I
+performed a fast-forward merge of the local ~elixir_releases~ branch into the
+~master~ branch. Etc.
This is some pretty powerful information for digging into the history of the
-repository. The reflog is indispensable for working out how to recover lost
+repository. The reflog is indispensable for working out how to recover lost
changes.
-## Git Fsck ##
+** Git Fsck
+ :PROPERTIES:
+ :CUSTOM_ID: git-fsck
+ :END:
-[`git-reflog(1)`][1] is a very useful tool, but, another way history can be
-lost is by becoming "unreachable".
+[[man-git-reflog][~git-reflog(1)~]] is a very useful tool, but, another way
+history can be lost is by becoming "unreachable".
-This is where [`git-fsck(1)`][3] can help! [`git-fsck(1)`][3] searches the Git
-object store, and will report objects that are dangling or unreachable from a
-named reference. This way, we can find commits, or even blobs, that have been
-lost to us because they do not exist in the directed acyclic graph (DAG) of
-Git, but _do_ exist in the object store itself.
+This is where [[man-git-fsck][~git-fsck(1)~]] can help!
+[[man-git-fsck][~git-fsck(1)~]] searches the Git object store, and will report
+objects that are dangling or unreachable from a named reference. This way, we
+can find commits, or even blobs, that have been lost to us because they do not
+exist in the directed acyclic graph (DAG) of Git, but /do/ exist in the object
+store itself.
-For example, running `git fsck` on this repository yields the following output:
+For example, running ~git fsck~ on this repository yields the following output:
+#+BEGIN_EXAMPLE
± git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (150/150), done.
dangling commit 16f6063abde9dcd8279fb2a7ddd4998aaf44acc7
+#+END_EXAMPLE
-Now, if we add another option, namely, `--unreachable`, we get the following:
+Now, if we add another option, namely, ~--unreachable~, we get the following:
+#+BEGIN_EXAMPLE
± git fsck --unreachable
unreachable blob 20c1e21948ab5d9553c11fa8a7230d73055c207e
unreachable commit 16f6063abde9dcd8279fb2a7ddd4998aaf44acc7
unreachable commit 41a324739bc3f1d265ecc474c58256e3a4ad4982
unreachable blob c4131dc6d091b1c16943554fa2396f5d405e8537
+#+END_EXAMPLE
Furthermore, objects listed in the reflog are considered "reachable", but may
-be still eluding our search. Adding `--no-reflogs` to [`git-fsck(1)`][3] can
-help make these objects more visible:
+be still eluding our search. Adding ~--no-reflogs~ to
+[[man-git-fsck][~git-fsck(1)~]] can help make these objects more visible:
+#+BEGIN_EXAMPLE
± git fsck --unreachable --no-reflogs
unreachable commit 00fc0164a78fe6b46e56781d434fdbb893f11534
unreachable blob 18a484273f75e4a3dcac75cb5229a614f6090be0
@@ -154,19 +176,24 @@ help make these objects more visible:
unreachable blob d79fb0b95796290c33d6f3dee004235dad7d8893
unreachable commit dabb01b3df1371602f3f0689d25359597db54423
unreachable blob ec2ba85be58685070a44727bc2591b9a32eb6457
+#+END_EXAMPLE
-Using these hashes, one could inspect them using other [familiar tools][4],
-namely, [`git-show(1)`][5] and [`git-cat-file(1)`][6] to figure out if these
-are worth resurrecting or even are in fact the objects we want to resurrect.
+Using these hashes, one could inspect them using other
+[[kb-git-in-reverse][familiar tools]], namely, [[man-git-show][~git-show(1)~]]
+and [[man-git-cat-file][~git-cat-file(1)~]] to figure out if these are worth
+resurrecting or even are in fact the objects we want to resurrect.
-## Resurrection Example ##
+** Resurrection Example
+ :PROPERTIES:
+ :CUSTOM_ID: resurrection-example
+ :END:
Now that we have some tools, let's examine a situation where a change to the
history was made that needs to be corrected: deleting branch references.
Let's assume we are working on a topic branch for some new awesome feature.
However, after some developing, we discover this solution might not be worth
-pursuing anymore. In a fit of rage of our wasted effort, we dump the branch.
+pursuing anymore. In a fit of rage of our wasted effort, we dump the branch.
Perhaps several days go by, and we discover we want to look back at something
we did in that previous branch for some reason or another, but we certainly
@@ -174,6 +201,7 @@ don't remember the commit hash of that branch.
For concreteness, let's create a repository that will demonstrate this problem:
+#+BEGIN_EXAMPLE
$ cd $(mktemp -d)
$ git init foobar
$ cd foobar
@@ -186,13 +214,17 @@ For concreteness, let's create a repository that will demonstrate this problem:
± git log --oneline
1cf706a add bar
11d3501 initial commit
+#+END_EXAMPLE
-> I created this example repository in a temporary directory because it's not
-> likely to be useful after the demonstration of this problem. Feel free to
-> create the repository wherever you please, provided you are following along.
+#+BEGIN_QUOTE
+ I created this example repository in a temporary directory because it's not
+ likely to be useful after the demonstration of this problem. Feel free to
+ create the repository wherever you please, provided you are following along.
+#+END_QUOTE
From here, we may decide to branch and start working on our epic topic branch:
+#+BEGIN_EXAMPLE
± git checkout -b topic/epic_feature
± echo 1 >> foo
± git commit -am 'update foo: add 1'
@@ -207,39 +239,50 @@ From here, we may decide to branch and start working on our epic topic branch:
32d8e6d update foo: add 1
1cf706a add bar
11d3501 initial commit
+#+END_EXAMPLE
-From here, we decide that the `topic/epic_feature` branch is going anywhere but
-the `master` branch. Therefore, we, swiftly, dump it into the ether:
+From here, we decide that the ~topic/epic_feature~ branch is going anywhere but
+the ~master~ branch. Therefore, we, swiftly, dump it into the ether:
+#+BEGIN_EXAMPLE
± git checkout master
Switch to branch 'master'
± git branch -D topic/epic_foobar
Deleted branch topic/epic_feature (was 2e0bcc6).
+#+END_EXAMPLE
Several days pass, we perform other commits on other branches, merge them into
-`master`, decide on some other things to work on. But eventually, we are
-reminded that our old `topic/epic_feature` branch had something similar to what
-we are doing now. It would be nice to recover it and its changes for
-examination. However, we likely lost the commit hash of the branch.
+~master~, decide on some other things to work on. But eventually, we are
+reminded that our old ~topic/epic_feature~ branch had something similar to what
+we are doing now. It would be nice to recover it and its changes for
+examination. However, we likely lost the commit hash of the branch.
-### Solution ###
+*** Solution
+ :PROPERTIES:
+ :CUSTOM_ID: solution
+ :END:
-If we take a quick look at our `git-fsck` output, we might see something that
+If we take a quick look at our ~git-fsck~ output, we might see something that
may lead us to our commit hash:
+#+BEGIN_EXAMPLE
± git fsck
Checking object directories: 100% (256/256), done.
+#+END_EXAMPLE
-Well, that was less than helpful. What happened? Turns out, as mentioned
-above, `git-fsck` considers objects "reachable" if they are pointed to by a
-reference _or_ are in the reflog. Let's add the `--no-reflogs` flag:
+Well, that was less than helpful. What happened? Turns out, as mentioned
+above, ~git-fsck~ considers objects "reachable" if they are pointed to by a
+reference /or/ are in the reflog. Let's add the ~--no-reflogs~ flag:
+#+BEGIN_EXAMPLE
± git fsck --no-reflogs
Checking object directories: 100% (256/256), done.
dangling commit 2e0bcc62122f2d7bf895958ac8fed1ec05d4d904
+#+END_EXAMPLE
This looks more promising! Let's checkout this hash and inspect it:
+#+BEGIN_EXAMPLE
± git checkout 2e0bcc62122f2d7bf895958ac8fed1ec05d4d904
Note: checking out '2e0bcc62122f2d7bf895958ac8fed1ec05d4d904'.
@@ -260,13 +303,17 @@ This looks more promising! Let's checkout this hash and inspect it:
32d8e6d update foo: add 1
1cf706a add bar
11d3501 initial commit
+#+END_EXAMPLE
-This indeed looks like the branch we created (several days) before. Git's
+This indeed looks like the branch we created (several days) before. Git's
interface, as a helpful reminder, explains to us how to (re)create this point
-as a reference (branch). It is, thus, our choice to examine the branch as-is,
+as a reference (branch). It is, thus, our choice to examine the branch as-is,
or recreate the reference for later inspection.
-## Another Resurrection Example ##
+** Another Resurrection Example
+ :PROPERTIES:
+ :CUSTOM_ID: another-resurrection-example
+ :END:
For another example, let's examine when we create a branch and change the
parent commit of the branch point.
@@ -274,6 +321,7 @@ parent commit of the branch point.
We will start with some commands that create and initialize the repository into
an initial state, that is, before any mistakes are made:
+#+BEGIN_EXAMPLE
$ cd $(mktemp -d)
$ git init foobar
$ cd foobar
@@ -288,33 +336,42 @@ an initial state, that is, before any mistakes are made:
± git checkout -b topic/foobar
± echo 1 >> bar
± git commit -am 'update bar: add 1'
+#+END_EXAMPLE
-> Notice, again, I've created this repository in a temporary directory for my
-> own system's tidyness. Futhermore, note `mktemp -d` will create a _different_
-> temporary directory. As such, the `foobar` project from this example and the
-> previous example _will_ be different.
+#+BEGIN_QUOTE
+ Notice, again, I've created this repository in a temporary directory for my
+ own system's tidyness. Futhermore, note ~mktemp -d~ will create a
+ /different/ temporary directory. As such, the ~foobar~ project from this
+ example and the previous example /will/ be different.
+#+END_QUOTE
From here, our one line log should look similar to the following:
+#+BEGIN_EXAMPLE
± git log --oneline
3de2659 update bar: add 1
5e6dd5f update foo: add 1
9640abb add bar
31d2347 initial commit
+#+END_EXAMPLE
Furthermore, here is an image that describes the state of the repository.
-{{< figure src="/media/git-repo-state-1.svg"
- alt="Example Repository State 1" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State 1
+[[file:/media/git-repo-state-1.svg]]
+#+HTML: </figure>
Next, we will create a few more commits, but instead of doing things properly,
-we are going to (intentionally) make a mistake. We will merge our
-`topic/foobar` branch into `master`, create a new file, `foobar`, and create a
-branch, `topic/bad`, from `topic/foobar`. In the `topic/bad` branch, we will
-create some new commits, but then we will squash the _two previous_ commits.
+we are going to (intentionally) make a mistake. We will merge our
+~topic/foobar~ branch into ~master~, create a new file, ~foobar~, and create a
+branch, ~topic/bad~, from ~topic/foobar~. In the ~topic/bad~ branch, we will
+create some new commits, but then we will squash the /two previous/ commits.
Let's begin issuing commands against our repository:
+#+BEGIN_EXAMPLE
± git checkout master
± git merge --ff-only topic/foobar
± touch foobar
@@ -325,69 +382,88 @@ Let's begin issuing commands against our repository:
± git commit -am 'update foo: add 2'
± echo 2 >> bar
± git commit -am 'update bar: add 2'
+#+END_EXAMPLE
Thusly, our repository should look similar to the following image:
-{{< figure src="/media/git-repo-state-2.svg"
- alt="Example Repository State 2" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State 2
+[[file:/media/git-repo-state-2.svg]]
+#+HTML: </figure>
Now, for the mistake:
+#+BEGIN_EXAMPLE
± git rebase -i HEAD~3
(squash the previous commits)
pick 3de26
squash 4babf
squash 7647f
+#+END_EXAMPLE
This should result in a repository that looks like the following:
-{{< figure src="/media/git-repo-state-3.svg"
- alt="Example Repository State 3" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State 3
+[[file:/media/git-repo-state-3.svg]]
+#+HTML: </figure>
Assuming we didn't recognize the mistake, we might attempt to merge the branch:
+#+BEGIN_EXAMPLE
± git checkout master
± git merge --ff-only topic/bad
fatal: Not possible to fast-forward, aborting.
+#+END_EXAMPLE
-Well, of course, the `master` branch is ahead by one commit, and the
-`topic/bad` branch is "behind" by two.
+Well, of course, the ~master~ branch is ahead by one commit, and the
+~topic/bad~ branch is "behind" by two.
-We can see this be viewing the logs when going from `master` to `topic/bad` and
+We can see this be viewing the logs when going from ~master~ to ~topic/bad~ and
then vice-versa:
+#+BEGIN_EXAMPLE
± git log --oneline master..topic/bad
3b71666 update bar: add 1
± git log --oneline topic/bad..master
7387d60 add foobar
3de2659 update bar: add 1
+#+END_EXAMPLE
But another issue emerges from viewing these log outputs from our mistake
ignorant brains: two of the commits look the same, e.g., have the same commit
message.
-Not only have we combined two of our changes from `topic/bad` but we combined
-them with a commit that was _already_ merged into the `master` branch. Assuming
-`master` is a stable and "branchable" branch, we will not be able to simply
-rebase one way and return, the commits are too intermingled.
-
-> Branchable, in this context, means the branch is safe to base work, no one on
-> our team (or ourselves, if we practice proper discipline) will come behind us
-> and change the history of this branch. This is an important assumption in
-> _any_ distributed workflow. Every project should have (at least) one
-> "branchable" reference, many choose this to be the `master` branch.
-
-### Solutions ###
-
-One way we can fix this is to simply not care. But that's not what we are
+Not only have we combined two of our changes from ~topic/bad~ but we combined
+them with a commit that was /already/ merged into the ~master~ branch.
+Assuming ~master~ is a stable and "branchable" branch, we will not be able to
+simply rebase one way and return, the commits are too intermingled.
+
+#+BEGIN_QUOTE
+ Branchable, in this context, means the branch is safe to base work, no one on
+ our team (or ourselves, if we practice proper discipline) will come behind us
+ and change the history of this branch. This is an important assumption in
+ /any/ distributed workflow. Every project should have (at least) one
+ "branchable" reference, many choose this to be the ~master~ branch.
+#+END_QUOTE
+
+*** Solutions
+ :PROPERTIES:
+ :CUSTOM_ID: solutions
+ :END:
+
+One way we can fix this is to simply not care. But that's not what we are
about: we like clean history, this situation and such a solution is clearly not
clean!
-Therefore, we will have to return the `topic/bad` branch to a clean state
+Therefore, we will have to return the ~topic/bad~ branch to a clean state
before continuing with merging the work done in the branch.
Let's start with examining the reflog:
+#+BEGIN_EXAMPLE
± git reflog
7387d60 HEAD@{0}: checkout: moving from topic/bad to master
3b71666 HEAD@{1}: rebase -i (finish): returning to refs/heads/topic/bad
@@ -407,11 +483,13 @@ Let's start with examining the reflog:
5e6dd5f HEAD@{14}: commit: update foo: add 1
9640abb HEAD@{15}: commit: add bar
31d2347 HEAD@{16}: commit (initial): initial commit
+#+END_EXAMPLE
-Examining `HEAD@{5}` we will see the commit of `topic/bad` _before_ we
-attempted to rebase the three commits. If we start there, we may be able to
+Examining ~HEAD@{5}~ we will see the commit of ~topic/bad~ /before/ we
+attempted to rebase the three commits. If we start there, we may be able to
salvage the history.
+#+BEGIN_EXAMPLE
± git checkout topic/bad
± git reset --hard 7647f9c
± git log --oneline
@@ -421,22 +499,29 @@ salvage the history.
5e6dd5f update foo: add 1
9640abb add bar
31d2347 initial commit
+#+END_EXAMPLE
-> Obligatory notice, blindly using `git reset --hard` can lead to dark, scary
-> places. As with the first example in this post, `git reset --hard` is an even
-> more subtle way to lose commits. Pause before pressing enter _everytime_ you
-> type `git reset --hard`.
+#+BEGIN_QUOTE
+ Obligatory notice, blindly using ~git reset --hard~ can lead to dark, scary
+ places. As with the first example in this post, ~git reset --hard~ is an
+ even more subtle way to lose commits. Pause before pressing enter
+ /every time/ you type ~git reset --hard~.
+#+END_QUOTE
Perfect, we are back to the state of the branch as seen in the following image:
-{{< figure src="/media/git-repo-state-2.svg"
- alt="Example Repository State Before Mistake" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State Before Mistake
+[[file:/media/git-repo-state-2.svg]]
+#+HTML: </figure>
From here, we can merge the two branches however we please: rebase and
fast-forward or regular old merge commits.
The first way of merging the two branches may proceed as follows:
+#+BEGIN_EXAMPLE
± git branch
topic/bad
± git rebase master
@@ -451,17 +536,24 @@ The first way of merging the two branches may proceed as follows:
bar | 1 +
foo | 1 +
2 files changed, 2 insertions(+)
+#+END_EXAMPLE
Afterwards, our repository will look like the following figure:
-{{< figure src="/media/git-repo-state-4.svg"
- alt="Example Repository State After Rebase Fast-Forward Merge" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State After Rebase Fast-Forward Merge
+[[file:/media/git-repo-state-4.svg]]
+#+HTML: </figure>
-> If we wanted to rebase the two commits from `topic/bad` together, we could
-> have easily done so _right_ before switching to the `master` branch.
+#+BEGIN_QUOTE
+ If we wanted to rebase the two commits from ~topic/bad~ together, we could
+ have easily done so /right/ before switching to the ~master~ branch.
+#+END_QUOTE
Proceeding with a regular merge commit would proceed similar to the following:
+#+BEGIN_EXAMPLE
± git checkout master
Switched to branch 'master'
± git merge --no-ff topic/bad -m 'merge branch "topic/bad"'
@@ -469,57 +561,47 @@ Proceeding with a regular merge commit would proceed similar to the following:
bar | 1 +
foo | 1 +
2 files changed, 2 insertions(+)
+#+END_EXAMPLE
Afterwards, our repository will look like the following figure:
-{{< figure src="/media/git-repo-state-5.svg"
- alt="Example Repository State After Merge Commit" >}}
+#+ATTR_HTML: :align center
+#+HTML: <figure>
+#+NAME: fig: Example Repository State After Merge Commit
+[[file:/media/git-repo-state-5.svg]]
+#+HTML: </figure>
-## Summary ##
+** Summary
+ :PROPERTIES:
+ :CUSTOM_ID: summary
+ :END:
The best way to fix Git repository history is not to make mistakes in the first
-place. However, since mistakes are inevitable, we must learn the tools to
+place. However, since mistakes are inevitable, we must learn the tools to
discover, recover, and return to the appropriate state to correct our mistakes.
More importantly, we must learn the courage to make mistakes, knowing we have
an escape route.
-This way, we can avoid keeping around a `git.txt` file ([xkcd][9]) when our
-repository eventually melts down.
-
-## References ##
-
-* [`git-reflog(1)`][1]
-
-* [Git SCM book, Internals Chapter][2]
-
-* [`git-fsck(1)`][3]
-
-* [Git in Reverse][4]
-
-* [`git-show(1)`][5]
-
-* [`git-cat-file(1)`][6]
-
-* [`git-reset(1)`][7]
+This way, we can avoid keeping around a ~git.txt~ file ([[xkcd-git][xkcd]])
+when our repository eventually melts down.
-* [`git-rebase(1)`][8]
+** References
-* [XKCD: Git][9]
+- [[man-git-reflog][~git-reflog(1)~]]
-[1]: https://www.kernel.org/pub/software/scm/git/docs/git-reflog.html
+- [[git-scm-book-internals][Git SCM book, Internals Chapter]]
-[2]: https://git-scm.com/book/en/v2/Git-Internals-Git-References
+- [[man-git-fsck][~git-fsck(1)~]]
-[3]: https://www.kernel.org/pub/software/scm/git/docs/git-fsck.html
+- [[kb-git-in-reverse][Git in Reverse]]
-[4]: https://kennyballou.com/blog/2016/01/git-in-reverse/
+- [[man-git-show][~git-show(1)~]]
-[5]: https://www.kernel.org/pub/software/scm/git/docs/git-show.html
+- [[man-git-cat-file][~git-cat-file(1)~]]
-[6]: https://www.kernel.org/pub/software/scm/git/docs/git-cat-file.html
+- [[man-git-reset][~git-reset(1)~]]
-[7]: https://www.kernel.org/pub/software/scm/git/docs/git-reset.html
+- [[man-git-rebase][~git-rebase(1)~]]
-[8]: https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html
+- [[xkcd-git][XKCD: Git]]
-[9]: https://xkcd.com/1597