Many Git commands are difficult to master completely by rote memorization. In this article, we will start with the working principle of common commands to thoroughly master these commands. Before we start this article, we can try to answer the following questions:

  • Whether or not to understandThe workspace,The staging area,warehouseThe difference between?
  • GitHow do the common commands in the three regions work?
  • How are branches merged? How does it work?
  • Branch mergingrebaseandmergeThe difference between?

If you feel very vague, then it is recommended to read the article carefully

Three partitions

Let’s start with a diagram to understand the locations of workspaces, staging areas, and warehouses:

Git commit commits the snapshot generated by the staging area to the local repository. Finally, use git push to copy the commit from the local repository to the remote repository. Online repositories like Github.

Git pull is used to pull the latest commit from a remote repository to a local repository. Git reset — files is used to undo the last git add files. Git checkout — files copies files from the staging area to the workspace to discard local changes (that is, overwrite changes that have not yet been added to the staging area).

The working principles of common commands

To start with an appetizer:

diff

Git diff: Git diff: Git diff: Git Diff: Git Diff

  • git diff, without any parameters, the workspace (noadd) and temporary storage area;
  • git diff HEAD, the workspace withHEADPointer pointedcommitFor comparison, generally speaking, our current changes are inHEADPoint to thecommitOn the basis of;
  • git diff --cached, will the staging area with the currentcommitMake a comparison;
  • git diff devTo connect the workspace to the latest target branchcommitMake a comparison;
  • git diff [commitId_1] [commitId_2], will be twocommitCompare.

commit

Previously we said that a commit generates a snapshot in the staging area and pushes it to the local repository. Here we consider committing in three cases:

  • The currentHEADtrailingcommit:

  • The currentHEADcentral-pointingcommit, the commit will split off a new route, so subsequent branch merges will inevitably come in handy.

  • You want to overwrite the previous commit with a new commit: git commit –amend:

For example, if you make a git commit and then commit something, you will use two commits for the wrong change, which will look ugly in the git log. It may not matter if you make a small demo by yourself. For large projects or open source projects that already have a lot of commits, adding them randomly is unacceptable.

As shown in the figure above, our new commit is replaced by the original commit, and the old commit is discarded.

checkout

When we use git checkout [branch_name] to switch branches, it looks like this:

The dev branch copies the contents to the staging area and workspace, overwriting the master version, and deleting files that only exist in the master.

reset

The following figure shows the rollback situation. Please take a closer look at the description below for the three specific situations:

  • git reset [commitId] --sortThis is the weakest rollback mode and only changescommitInformation, does not affectThe staging areaandThe workspace;
  • git reset [commitId]If no parameter is specified, only rollback is performed by defaultThe staging area, that is, thedks8vIs copied toThe staging areaBut it does not affectThe workspace;
  • git reset [commitId] --hardThis way, the rollback can be doneThe workspaceandThe staging area.

merge

Git merge -s: Git merge -s: Git merge -s: Git merge -s: Git merge

Fast-forward

Git merge dev is the parent of the master branch. Git merge dev is the parent of the master branch. Git merge dev is the parent of the master branch. Fast-forward is the default behavior when Git merges two unforked branches.

Recursive

Recursive is the default behavior of Git when merging two branches that bifurcate. In simple terms, it is a Recursive three-way merge.

There is a new term, three-way merge, which is the focus of our next discussion. Let’s figure out what the integrated link is.

  • First of all,devThe branchc5k8xwithHEADPoint to thesf22x, plus their most recent common ancestora23c4Carry out a three-way merge first;
  • Then copy the merged results to staging and workspace;
  • A new commit is then generated with an ancestor ofdevandThe original master;

The principle of branch merging

First, let’s look at how the two files are merged:

If we were to merge two versions of A/B, we would need to determine whether A changed B, B changed A, or both, in which case it would be impossible to tell.

Therefore, to achieve a merge of two files, we introduce a three-way merge:

As shown in the figure below, it is clear that version A is the same as Base version, and version B is modified more recently than version A. Therefore, after A/B is merged, version B is obtained.

The intelligent reader will look at the above example and wonder, what if A/B and Base are different? So that’s what we’re going to talk about.

conflict

When a situation like the one below occurs, manual conflict resolution is usually required.

This is what we tend to see when merging code:

<<<<<<< HEAD
print("hello")
=======
print("fxxk")
>>>>>>> B
Copy the code

For starters, this arrow might be a little confusing, but which is which? ======= in the middle is the delimiter, the content between <<<<<< at the top is the HEAD version, which is the current branch of master, and the content between >>>>>> at the bottom is the branch of B. We just need to delete the arrow and keep the required version:

print("hello")
Copy the code

Final merge result:

Recursive three-way merge

In the actual production environment, Git branches are often very complicated, resulting in the merger of A/B, multiple A/B common ancestor can be found, and the so-called recursive three-way merger is to continue to find the common ancestor of their common ancestor until the only common ancestor is found, which can reduce the probability of conflict.

As shown in the figure above, to merge 5 and 6, we need to first find the common ancestor of 5/6 — 2 and 3, and then continue to find the common ancestor — 1. When we find the only ancestor, we start the recursive three-way merge, and first do the three-way merge of 1, 2 and 3, and get the temporary node 2’/B:

Then continue the three-way combination of 2, 5 and 6 to get 7/C:

rebase

Git rebase master: Git rebase master: Git rebase master: Git rebase master

Select a23C4, parent of dev and master, and insert all nodes from a23C4 to dev’s path back to master. Note that commitId will change during replication. Meanwhile, nodes on the dev old branch are discarded because they have no references.

conclusion

Review the questions you asked at the beginning, and I’m sure you’ll be able to answer them after reading this article carefully. This article will focus more on how Git works, but we haven’t covered the underlying principles yet. We’ll talk about how Git stores files at some point in the future.

This article is excerpted from: Programming power Bank