History Exploring the Past - aakash14goplani/FullStack GitHub Wiki

Topics Covered

A Commit by Any Other Name

  • Here is our cookbook repository. I will checkout one of the existing branches. This branch here called nogood. I'm just looking for any old bunch of commits here. I can use git log to look at the history, but the problem is the default in git log is not very useful when you're trying to make sense of a complex history because it squashes everything in a single list, so it's hard to make sense of branches and merges and understand what really happened. So I will use git log with a few options.

  • The graph option gives me a nice graph-like structure where I can see how the commits and branch emerge and the decorate option shows the positional references like branches had. And finally, I will format the log so that each commit takes only one line.

$ git log --graph --decorate --oneline

There, beautiful. We can see the structure of the repository now, all the references including path, branches, remote branches, the works. image 1

  • Let's say that I want to see information about the current commit. I want to know which changes were introduced by this commit, the date of the commit, and so on. I can use the git show command to do that. Of course, I need to tell it which commit I want to look at. How can I refer to this commit? The obvious way is to use its hash like we did in the past or better the first few characters of the hash like this.
$ git show 7160d61

image 2

  • However, using hashes is not always the easiest or most practical way to refer to a commit. Another way to do that is to give Git the name of a reference to this pointing at the commit. The nogood branch, for example, is pointing at this commit, so I can use the branch to refer to the commit. better the first few characters of the hash like this.
$ git show nogood

image 3

  • Also, head is pointing at the branch that is pointing at the commit. This is the current commit at the moment, so I can also refer to it through head. better the first few characters of the hash like this.
$ git show HEAD

image 4

  • What if we want to reference a87f2cc other commit, the second last one? There is no reference pointing at it, so it seems that our only option is to use its hash. However, there are other ways. I can start at head and add a caret (^). The caret means the parent commit, so now I'm asking for the parent commit of head.
$ git show HEAD^
  • And if I want to refer to ecbebe commit here, third commit, then I can use two carets. This means go to the parent of the parent of head.
$ git show HEAD^^
  • I can also say the exact same thing by using a tilde (~) sign followed by a number. You can read these as go to head and then go back to commits. This is useful, especially if you want to look at say the 10s commit before head and you don't want to tie 10 carets. You can just say ~10.
$ git show HEAD~2

image 5

  • This syntax is fine if each commit has exactly one part, but it breaks down as soon as you have commits with multiple parts like this merge commit. What if I were to refer to 007ffe9 commit, for example. It's the second parent of the second commit before head. In this case, I can direct it with this syntax. Let's see. Start from head, then go back to commits, and then pick the second part.
$ git show HEAD~2^2

image 6

  • There are other even more sophisticated ways to refer to commit. I just asked Git to show me where head was one month ago.
$ git show HEAD@{"1 month ago"}

image 7

History Forensics

  • Let's talk about commits are connected. There are a few useful commands for that, one is git blame. This shows you where the lines in the file are coming from. Let's see who changed the menu.txt file and when. Here are all the lines in the file.
$ git blame menu.txt

image 8

  • For each line, you can see the latest commit where that line was changed.

    • The caret here means that this is the first commit that added this line to the repository, so these lines they're in the file since the first time the file was added to the project and all the other lines were changed or added in some secret commits.
    • And here I can see the date and the old source of these changes, knew there was always my file partly change my name in my Git configuration after creating the file.
  • Another useful command is git diff. We already used git diff to compare the content of two areas like the repository and the index, but you can also use it to compare other things. For example, to commit, let's see the differences between the current commit and two commits earlier.

$ git diff HEAD HAED~2

image 9

  • And of course, you can use branches to reference commits, so one common technique is using git diff to compare to branches. This shows all the changes between the two branches. This is very useful. Comparing branches is really useful, especially before merging stuff.
$ git diff master spaghetti

Browsing the Log

  • Git log is the most useful command for exploring a project's history. Let's discuss a few examples.

  • To begin with, you can get the detail diff for each commit in log like these, so you can see exactly which changes were introduced in the commit. It's also very colorful.

$ git log --patch

image 10

  • One more option, you can filter the commits. For example, I only want to see the commits that contain the string images in their message and there is only one of them.
$ git log --grep images --oneline

image 11

  • You can even ask for all the commits that added or removed the word git for many file with -G uppercase.
$ git log --G git

image 12

  • As an alternative, there is also a git grep command that is useful for this kind of history-wide text searches. Check it out if you wish.

  • Git log can also visualize a specific range of commits. The easiest way to do this is to say, for example, git log -M, which means only show me the letters M commits in the log.

$ git log --3 --oneline

image 13

  • You can also use two dots to express a range like this. This means shows me the commits from 3 commits before head to the HEAD(parent of a head = HEAD^ i.e. one commit before HEAD, current commit = HEAD). I used to find this range syntax mildly confusing because you specify the oldest commit first here, but in the default git log output, the commits are reversed, so you see the oldest commit at bottom is that.
$ git log HEAD~3..HEAD --oneline

image 14

  • This commit arrange feature is particularly useful if you need to compare it to branches. This is a common scenario. This is not like a diff. It's a different kind of comparison. A diff can compare the files into branches, here we want to compare the histories of two branches. It's easier to understand with an example. For example, the current branch is the nogood branch. Let's say that I want to list the commits that are in the master branch, but not in the nogood branch. So you can read these as go from nogood to master and show me all the new commits that you see and here they are. If we make master right now, then these are the commits that we would get.
$ git log nogood..master --oneline

image 15

  • Git log has a huge amount of options to show your history in a number of different ways to filter commits, to format them, and so on.
⚠️ **GitHub.com Fallback** ⚠️