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 understand
The workspace
,The staging area
,warehouse
The difference between? Git
How do the common commands in the three regions work?- How are branches merged? How does it work?
- Branch merging
rebase
andmerge
The 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 withHEAD
Pointer pointedcommit
For comparison, generally speaking, our current changes are inHEAD
Point to thecommit
On the basis of;git diff --cached
, will the staging area with the currentcommit
Make a comparison;git diff dev
To connect the workspace to the latest target branchcommit
Make a comparison;git diff [commitId_1] [commitId_2]
, will be twocommit
Compare.
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 current
HEAD
trailingcommit
:
- The current
HEAD
central-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] --sort
This is the weakest rollback mode and only changescommit
Information, does not affectThe staging areaandThe workspace;git reset [commitId]
If no parameter is specified, only rollback is performed by defaultThe staging area, that is, thedks8v
Is copied toThe staging areaBut it does not affectThe workspace;git reset [commitId] --hard
This 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,
dev
The branchc5k8x
withHEAD
Point to thesf22x
, plus their most recent common ancestora23c4
Carry out a three-way merge first; - Then copy the merged results to staging and workspace;
- A new commit is then generated with an ancestor of
dev
andThe 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