Skip to content

Latest commit

 

History

History
82 lines (49 loc) · 5.43 KB

File metadata and controls

82 lines (49 loc) · 5.43 KB

Day 12: Understanding Git Object Relative Names

After understanding the "absolute names" and "reference names" of Git objects, we will now introduce "relative names," which are also commonly used in the Git version control process.

Let's review again. In Git version control, each version represents a commit object. Each commit object has an "absolute name" - a 40-character string obtained by SHA1 hashing the content. You can use the first 4 to 40 characters as the identification name of that commit object. During version control, you can also use "reference names" to represent a specific commit object. Each "reference name" ultimately corresponds to the "absolute name" of an object. "Reference names" are further divided into "general references" and "symbolic references." Among them, "general references" directly correspond to "absolute names," while "symbolic references" correspond to another "general reference."

What this article will introduce is the use of "relative name" notation, which allows you to find other "commit objects" based on their relative positions after finding a specific commit object.

Relative Name Notation

Using relative names is actually very simple. There are two special symbols you must remember, one is ^ and the other is ~.

To find the previous version of HEAD, we will use HEAD~ or HEAD~1 to represent "the previous version of the HEAD commit object." Note: Here you should already know very well that HEAD is a built-in "symbolic reference name" in Git, representing the latest version of the current branch.

If you want to find the two versions before another f2e branch (not including the HEAD version of f2e), you can use f2e~2 or f2e~~ to represent it. This is the most basic representation method.

In repositories without branches and merges, the meaning expressed by ^1 and ~1 is exactly the same, both representing the "previous version." But in fact, in repositories with branches and merges, they have different meanings. This part will be explained later.

This is the most basic "relative name" notation.

Links Between Commit Objects

In more common Git repositories, there will only be one "root commit object" by default, which is the first version we created, also known as the "Initial Commit." You also need to have at least the first commit object before you can start branching. So we can say: "In a Git repository, among all commit objects, except for the first commit object, any other commit object must have one or more parent commit objects." Why might there be "more than one" parent commit object? Because you are very likely to merge two or more branches into another branch. So the commit object after the merge will have multiple parent commit objects.

Let's use a simple example to prove this. We use git cat-file -p [object_id] to get the content of the first two commit objects, thereby understanding that each commit object will indeed have a parent attribute pointing to the absolute name of the parent commit object, except the first commit object will not have a parent attribute. As shown in the following figure:

image

Understanding the Difference Between ^ and ~ in Relative Name Notation

The meaning of ~ represents the "first parent commit object."

The meaning represented by ^ is "when there are multiple parent commit objects, which first-generation parent object to represent."

If you have a "reference name" of C, to find its first parent commit object, you can have the following expressions:

  • C^
  • C^1
  • C~
  • C~1

If you want to find its second parent commit object (without merging), you can have the following expressions:

  • C^^
  • C^1^1
  • C~2
  • C~~
  • C~1~1

But you cannot use C^2 to express the "second parent commit object"! The reason is that without merging, this C only has one parent object. You can only use C^2 to represent "the second parent object of the previous layer object."

The above may sound a bit abstract and tongue-twisting. I specially drew a diagram for you to see. Through the diagram, it may be clearer. As shown in the following figure, we want to find other commit objects (parent objects) in the relative path of the C commit object. Since this C commit object has three parent objects, this means that this commit object was created through merging. Then to find each path through "relative names," you must use a combination of ^ and ~ skills to locate each version you want to open.

image

Introducing the git rev-parse Command

In the Git for Windows tool, there is a git rev-parse command. Through this command, you can parse any "reference name" or "relative name" into an "absolute name." Although this tool is not used very often, it is quite practical when teaching Git. Usage examples are as follows:

  • git rev-parse master
  • git rev-parse HEAD
  • git rev-parse ORIG_HEAD
  • git rev-parse HEAD^
  • git rev-parse HEAD~5

Today's Summary

After understanding "relative names," various ways of representing commit objects in Git have been explained. I believe you should be able to better control operations between various versions of Git.

Let me reorganize the Git commands and parameters learned today:

  • git log
  • git cat-file -p [object_id]
  • git rev-parse