Since learning about git, I have always admired this software and want to write something to record what I have learned. Git is a version control software designed and released by Linus, the founder of Linux Kernal. At first glance, it is a stupid design. It is actually a masterpiece of genius. It is really wise. We all know that the traditional version control software includes CVs and SVN. However, compared with the same-source software, git stands out from the crowd and is proud of its model design.
First, let's talk about some basic concepts of git Model Design: git has designed several object models, which mainly include the size, type, and content of objects. Git contains three simple objects:
1. Blob: is used to store file data-it is generally a file
2. Tree: is basically like a directory-It references a bunch of other trees and/or blobs
3. Commit: points to a single tree, marking it as what the project looked like at a certain point in time
(Optional) 4. Tag: The tag object is a way to mark a specific commit as special in some way.
Taking common source code management as an example, blob objects are all object files in the project, including source code, image resources, xml configuration information, and so on, it is particularly emphasized that it only records the file content, and information about the Directory and name size of the file are all recorded on the tree object associated with it. Each commit generates a commit object and updates all tree objects associated with the modified file. In addition to managing blob, the tree can also manage the tree itself. Therefore, many tree objects record the information of all blob objects in the entire project, and form DAG (directed acyclic graph), so that at any point in time, the unique root node tree associated with the commit object can traverse and find all the files of the entire project in the commit state.
Reference the original article of a git authoritative book:
Git design split file name and content- file name saved in tree- file content saved in blob- so the same blob can stands for multi files with multi namesGit objects are immutable, that is, they cannot ever be changed.- There are references which also stored in Git. - Unlike the objects, references can constantly change.
So why can git become a leader in similar software? Is it because of the concise object definitions?
The author understands that the traditional version control software CVs and SVN are submitted after the file is modified, and then modified before submission. They only record the different states between files, that is, a file has only one copy since its creation. All subsequent changes are calculated from the original copy based on the record difference. Git's design philosophy is that any file, as long as there are any changes, even a byte, will re-create a copy (that is, the Blob mentioned earlier) object, if a file is modified four times, there will be four copies, each of which is independent and managed by the commit object generated each time the file is submitted. At first glance, this design of git consumes a lot of hard disks. It seems very dull! However, in today's computer era, the low cost of hard disks and the rapid expansion of capacity make the disk space consumption more and more insignificant. The GIT designer Linus makes full use of this and sacrifices the disk space in exchange
Flexible and efficient management over unlimited control. This is what I mentioned earlier: "wise and wise"
The following uses an example to describe how git works:
Suppose the directory structure in our project is like this:
- src- java- Hello.java- resource.xml- lib- rt.jar- run.bat
1. When we use git init to create a repository and submit the entire project for the first time, four blog objects will be created to Store Hello. Java, resource. XML, Rt. jar, and run. Bat respectively. And form a commit object and four tree objects (representing SRC, Java, Lib, and the root directory of the entire project, respectively ).
In this case, the default head in git points to the tree object submitted last time. Through checkout head, you can find all the files submitted last time. (In fact, all these objects are stored in the hidden directory. Git/objects)
2. now we only modify hello. for the second commit, git will generate a new BLOB Object Record after the modified hello. java, and generate a new commit object. Because blob only records the file content, other file information and directory structure are recorded by the tree object, so hello. as a result, the tree representing the Java directory is changed, and the tree object represented by the SRC parent directory is also changed. The same is true for the root directory, therefore, this commit will generate three new tree objects (representing the new SRC, the new Java, and the new project root directory root)
3. when another developer wants to get the state of the first commit of the project, they only need to provide the key of the first commit object, which records only the root tree of the first commit, this root tree will find the old SRC tree objects, Java tree objects and Lib tree objects that are not changed, and retrieve all the blog objects managed by them. So far, the entire project is checkout at the first submission. We can give a commit object an alias that is easy to remember, which forms the concept of tag and branch that we are familiar. The next time you provide an alias for checkout, you can.
What are the advantages of this design? In my understanding, it is very common for large projects to create branches. Git's complete model design gives developers the maximum flexibility to create branches and develop them on their own branches. When merge is required to reach the trunk for a certain period of time, unless the modification to the content of the same file needs to handle conflicts (merge two blob objects), the rest is only in the two trees of merge, update the pointer to blob and basic information of a few files in the directed acyclic graph tree to form a new tree! In actual project development, after all, different development methods for creating Branches develop a small number of new functions on the branches. Most of the content is different from the trunk. Therefore, when merge is a new tree, for unchanged blob objects, the trees before and after merge still point to them. For the modification files of their respective branches, only a small number of tree and blob are updated on merge to the trunk respectively. (If there is still some foundation for the data structure, try to draw a picture. You will find that merging two Directed Acyclic graphs is so simple and efficient)
At last, I attached some common git commands for experiment and reference: (I recommend a book about git, "Pro git". In the process of learning git, in fact, it is also learning how to develop efficient and practical software according to the evolution)
git cat-file -tgit ls-treegit showgit addgit commitgit commit -a git checkout HEADgit hash-object <file_name>git show -s --pretty=rawfind .git/objects/ -type fgit branch <branch_name>git branch - list all branchesgit branch -D <branch_name> (- delete a branch)git merge <branch_name> (- merge branch with name indicated into active branch)git checkbox <branch_name> - switch active branch, default is mastergit archivegit tag <name> (- this will indicated the lastest commit hash value, also called lightweight tag)git tag -a <name> (- will add a tag object, saved in .git/objects, cat-file will return "tag" type)