- Git:Mastering Version Control
- Ferdinando Santacroce Aske Olsson Rasmus Voss Jakub Nar?bski
- 5970字
- 2021-07-08 10:46:54
Chapter 2. Git Fundamentals – Working Locally
In this chapter, we will go deep into some of the fundamentals of Git. It is essential to understand how Git thinks about files, its way of tracking the history of commits, and all the basic commands that we need to master in order to become proficient.
Repository structure and file status life cycle
The first thing to understand while working with Git is how it manages files and folders within the repository. This is the time to analyze a default repository structure.
The working directory
In created an empty folder and initialized a new repository using the git init
command (in C:\Repos\MyFirstRepo
). Starting from now, we will call this folder the working directory. A folder that contains an initialized Git repository is a working directory. You can move the working directory around your file system without losing or corrupting your repository.
Within the working directory, you also learned that there is a .git
directory. Let's call it the git directory from now on. In the git directory there are files and folders that compose our repository. Thanks to this, we can track the file status, configure the repository, and so on.
File statuses
In used two different commands: git add
and git commit
. These commands allowed us to change the status of a file, making Git change its status from "I don't know who you are" to "You are in a safe place".
When you create or copy a new file in the working directory, the first state of the file is untracked. This means that Git sees that there is something new, but it won't take care of it (it would not track the new file). If you want to include the file in your repository, you have to add it using the add
command. Once it is added, the state of the file becomes unmodified. It means that the file is new (Git says it is unmodified because it never tracked changes earlier) and ready to be committed, or it has reached the staging area (also called index). If you modify a file that is already added to the index, it changes its status to modified.
The following screenshot explains the file status life cycle:

The staging area
The staging area or index is a virtual place that collects all the files you want to include in the next commit. You will often hear people talk about staged files with regard to Git, so take care of this concept. All the files (new or modified) you want to include in the next commit have to be staged using the git add
command. If you staged a file accidentally, you have to unstage it to remove it from the next commit bundle. Unstaging is not difficult; you can do it in many ways. Let me explain a few concepts. This several ways to do the same thing is an organic problem of Git. Its constant and fast evolution sometimes increases confusion, resulting in different commands that do the same thing. This is because it will not penalize people used to working in a particular manner, allowing them the time for some Git revision to understand the new or better way. Fortunately, Git often suggests the best way to do what you want to do and warns you when you use obsolete commands. When in doubt, remember that there are man pages. You can obtain some useful suggestions by typing git <command> --help
(-h
for short) and seeing what the command is for and how to use it.
Unstaging a file
Well, back to our main topic. Before continuing, let's try to understand the unstaging concept better. Open the repo folder (C:\Repos\MyFirstRepo
) in Bash and follow these simple steps:
- Be sure to be in a clean state by typing
git status
. If Git says "nothing to commit, working directory clean," we are ready to start. - Create a new file
touch NewFile.txt
. - Using
git status
again, verify thatNewFile.txt
is untracked. - Add it to the index so that Git can start tracking it. So, use the
git add NewFile.txt
command and go on. - When done, use the suggested
git reset HEAD <file>
command to back the file in the untracked status.
It should be clear now. It worked as expected: our file returned in the untracked state, as it was before the add
command.
Tip
Git reset
is a powerful command, and it can completely destroy your actual work if used improperly. Do not play with it if you don't know exactly what you are doing.
Another way to unstage a file that you just added is to use the git rm
command. If you want to preserve the file on your folder, you can use the --cached
option. This option simply removes it from the index, but not from the filesystem. However, remember that git rm
is to remove files from the index. So, if you use the git rm
command on an already committed file, you actually mark it for deletion. The next commit will delete it.
The time metaphor
Using the git reset
command, we also get in touch with another fundamental of Git, the HEAD
pointer. Let's try and understand this concept.
A repository is made of commits, as a life is made of days. Every time you commit something, you write a piece of the history.
The past
The past is represented by the previous commits that we did, as shown by C1 and C2 in the following diagram:

The HEAD
pointer is the reference to the last commit we did or the parent of the next commit we will do, as shown in the diagram:

So, the HEAD
pointer is the road sign that indicates the way to move one step back to the past.
The present
The present is where we work. When a previous commit is done, it becomes part of the past, and the present shows itself like this diagram:

We have a HEAD
reference that points out where we came from (the C2 commit). Resetting to HEAD
as we did earlier is a manner of going back in this initial state, where there are no modifications yet. Then, we have the working directory. This directory collects files added to the repository in the previous commits. Now, it is in the untouched state. Within this place, we do our work in files and folders, adding, removing, or modifying them.

Our work remains in the working directory until we decide to put it in the next commit we will perform. Using the git add
command, we add what we want to promote to the next commit, marking them into the index, as shown in this diagram:

With git rm --cached <file or folder>
, you can unstage a file by removing it from the index, as shown here:

With git reset --hard HEAD
, we will go back to the initial state, losing all the changes we made in the working directory.
At the end, once you commit, the present becomes part of the past. The working directory comes back to the initial state, where all is untouched and the index is emptied, as shown in this diagram:

The future
What about the future? Well, even though Git is a very powerful tool, it can't predict the future, not for now at least.
Working with repositories
Let's get our hands dirty!
If you are reading this book, you are probably a programmer, as I am. Using a programming language and its source and binary files to exercise could be fine. However, I don't want to distract you from understanding a language you probably don't use every day. So, let's settle things once and for all. When needed, I will use a nice markup language called Markdown (see http://daringfireball.net/projects/markdown/).
Apart from being simple yet powerful, Markdown silently became the favorite choice while typing readme
files (for example, GitHub uses it extensively) or comments in forums or other online discussion places, such as StackOverflow. Mastering it is not our goal, but to be able to do the basic things is surely a skill that can be useful in the future.
Before you proceed, create a new folder for exercises, for example, C:\Repos\Exercises
. We will use different folders for different exercises.
Unstaging a file
Consider the following scenario. You are in a new repository located in C:\Repos\Exercises\Ch1-1
. The working directory actually contains two files: first.txt
and second.txt
. You have accidentally put both first.txt
and second.txt
in the staging area, while you actually want to only commit first.txt
. So, now:
- Remove the
second.txt
file from the index - Commit the changes
The result of this is that only first.txt
will be a part of the commit.
Follow these simple steps to solve this simple task:
- Create the
C:\Repos\Exercises\Ch1-1
folder and open Bash inside it. - Use the
git init
command on the repository as we learned. - Create the
first.txt
andsecond.txt
files and add them to the staging area, as shown in the following screenshot:
At this point, remove the second.txt
file and commit. This time, try to use the handy git rm --cached
command, as suggested here:

Well done!
Viewing the history
Let's continue where we left off in Chapter 1, Getting Started with Git. Walk into C:\Repos\MyFirstRepo
and start a new Bash shell using the right-click shortcut. Now, use the git log
command to see the history of our repository, as shown in this screenshot:

The git log
command is very useful and powerful. With this command, we can get all the commits that we did one by one, each one with its most important details. It's now time to become more familiar with them.
Anatomy of a commit
Commits are the building blocks of a repository. Every repository is nothing more than an ordered sequence of commits. If you have a math background, you have probably already identified an acyclic direct graph in it.
The commit snapshot
Every time we commit something, Git wraps all the files included in a binary blob file. This is one of the most important characteristics of Git. While other versioning systems save files one by one (perhaps using deltas), Git produces a snapshot every time you commit, storing all the files you have included in it. You can assume that a snapshot is a commit, and vice versa.
The commit hash
The commit hash is the 40-character string we saw in logs. This string is the plate of the commit, the way we can refer to it unequivocally. We will not fail to use it in our little exercises.
Author, e-mail, and date
Git is for collaborating, too. So, it is important that every author signs every commit it does to make it clear who did what.
In every commit, you will find the author's friendly name and their e-mail to get in touch with them when necessary. If you are not happy with the actual author you see, change it with the git config
command, as shown here:

Configuring Git is quite simple. You have to know the name of the object to configure (user.name
in this example) and give it a git config <object> "<value>"
command. To change the e-mail, you have to change the user.email
configuration object.
If you want to see the value of an object, simply type git config <object>
and press Enter to get it.
There are three configuration levels: global, user, and repository. We will soon deal with Git configuration in more detail.
Commit messages
In the first chapter, we made two commits, and every time, we added a commit message. Adding a commit message is not only a good practice, it is mandatory. Git would not accept commits without a relative commit message. This is a thing I really appreciate. Let me explain it briefly.
In other versioning control systems, such as SVN, commit messages are optional. Developers, we all know, are lazy people. When they are in a hurry or under stress, the temptation to commit code without telling what feature of the software they are going to add, modify, improve or delete is strong. In no time, you build a mute repository with no change history, and you have to deal with commits that are difficult to understand. In other words, welcome to hell.
Committing a bunch of files
At this point, probably, you are wondering if there is a way to add more than one file at a time. Of course there is! With git add --all
(-A
), you add all of the files you have in your working directory to the index. You can also use <filepattern>
to add only certain types of files; for example, with git add *.txt
, you can add all text files to the index.
Ignoring some files and folders by default
Often, we work with temp or personal files that we don't want to commit in the repository. So, when you commit all files, it is useful to skip certain kinds of files or folders.
To achieve this result, we can create a .gitignore
file in the repository. Git will read it and then skip the files and folders we listed inside it.
Let's try to do this in our repository, C:\Repos\MyFirstRepo
. Perform the following steps:
- Browse to
C:\Repos\MyFirstRepo
. - Create a
.gitignore
file using your preferred editor. - Put this text inside it:
# === This is a sample of .gitignore file === # Ignore temp files *.tmp
- Save the file.
- Add the file to the index.
- Commit the
.gitignore
file. - Create a temp file
fileToIgnore.tmp
with a simpletouch
command. - Try to add all of the files in your working directory to the index and verify that Git will not add anything.
Note that .gitignore file
is not retroactive. If you have added some *.tmp
files to the index before introducing the .gitignore
file, they will stay under revision control. You have to remove them manually if you want to skip them.
The syntax of a .gitignore
file is quite simple. Lines starting with #
are comments, and they will be ignored. In each line of the file, you can add something to skip. You can skip a single file or folder, certain files by extension, as we did with *.tmp
files, and so on.
For the complete syntax of .gitignore
see http://git-scm.com/docs/gitignore.
Tip
To add a file in the .gitconfig
file even if it is marked to be ignored, you can use the git add -f
(--force
) option.
Highlighting an important commit – Git tags
We said that commits have an ID and a lot of other useful information bundled with binary blobs of files included. Sometimes, we want to mark a commit with a tag to place a milestone in our repository. You can achieve this by simply using the git tag –a <tag name>
command, using –m
to type the mandatory message:
$ git tag –a MyTagName –m "This is my first tag"
Tags will become useful in the future to keep track of important things such as a new software release, particular bug fixes, or whatever you want to put on evidence.
Taking another way – Git branching
Now, it's time to introduce one of the most used features of a versioning system: branching. This is a thing that you will use extensively and a thing that Git does well.
Anatomy of branches
A branch is essentially another way your repository takes. While programming, you will use branches to experiment with changes, without breaking the working code. You will use them to keep track of some extensive work, such as the development of a new feature, to maintain different versions or releases of your project. To put it simply, you will use it always.
When in a Git repository, you are always in a branch. If you pay attention to the Bash shell, you can easily find the branch that you are on at the moment. It is always at the prompt, within brackets, as shown here:

The master
branch is, conventionally, the default branch. When you do your first commit in a brand new repo, you actually do the first commit in the master
branch.
During the course of the book, you will learn that the master
branch will often assume an important role. We will only deploy code from that point, and we will never work directly in the master
branch.
Looking at the current branches
Let's start using the git branch
command alone. If you do this, you will get a list of the branches included in the current repository:
$ git branch
We will get the following response:

As expected, Git tells us that we have only the master
branch. The branch is highlighted with a star and green font just because this is our actual branch, the branch in which we are located at the moment.
Creating a new branch
Now, let's start creating a new branch for a new activity.
Open the Bash shell in C:\Repos\MyFirstRepo
and create a new branch from where you are using the git branch
command, followed by the name of the branch we want to create. Let's assume that the name of the branch is NewWork
:
$ git branch NewWork
Well, it seems nothing happened and we are still in the master
branch as we can see in the following screenshot:

Git sometimes is a man of few words. Type the git branch
command again to get a list of the actual branches:

Hey, there's a NewWork
branch now!
Switching from branch to branch
The only thing we have to do now is to switch to the NewWork
branch to begin working on this separate argument. To move around from one branch to another, we will use the git checkout
command. Type this command followed by the branch name to switch to:
$ git checkout NewWork
This time, Git gave us a short message, informing us that we have switched to the NewWork
branch. As you can see, NewWork
is within brackets in place of master, indicating the actual branch to us:

Super easy, isn't it?
Understanding what happens under the hood
At this point, nothing special seems to have happened. However, you will soon change your mind. Just to give you a visual aid, consider this figure:

Assume that our last commit on the master
branch was the C3 commit. At this point, we now have two other pointers: the master
branch pointer and the NewWork
branch pointer.
If you have used Subversion or a similar versioning system earlier, at this point, you would probably look for a NewWork
folder in C:\Repos\MyFirstRepo
. However, unfortunately, you will not find it. Git is different, and now, we will see why.
Now, to better understand what a branch is for, add NewWorkFile.txt
, stage it, and commit the work, as shown here:

At this point, we have a new commit in the NewWork
branch. This commit is not a part of the master
branch, because it has been created in another branch. So, the NewWork
branch is ahead of the master
branch, as shown in the following figure:

Working with Git in this kind of a situation is ordinary administration, just like it is in the day-to-day life of a developer. Creating a new branch is cheap and blazing fast even in large repositories, because all the work is done locally. You can derive multiple branches from a unique point, branch from a branch that branched into another branch, and so on, creating all the ramifications you can manage without going crazy.
Moving from a branch to another is easy. So, let's turn back to the master
branch and see what happens:

If you have used Subversion earlier, at this time, you are probably wondering at least two things: why is there no NewWork
folder containing files from that branch and, most of all, what was the fate of the NewWorkFile.txt
file.
In Apache Subversion (SVN), every branch (or tag) you checked out resides in a separate folder (bloating your repository, after some time). In Git, there is a huge difference. Every time you check out a branch, files and folders of the previous branch are replaced with those contained in the new branch. Files and folders only on the destination branch are restored, and those only on the previous branch are deleted. Your working directory is constantly a mirror of the actual branch. To have a look at another branch, you basically have to switch to it.
This aspect might look bad to you the first time, because seeing files and folders disappear is scary at first. Then, you can't differentiate the two branches as we probably did earlier by simply comparing the content of the two folders with your preferred tool. If I can give you a piece of advice, don't lose heart about this (as I did at the beginning): soon you will forget what you lost and you will fall in love with what you gained.
A bird's eye view to branches
So, let's go back once again to the NewWork
branch and have a look at the situation with the aid of a visual tool, Git GUI. Open the C:\Repos\MyFirstRepo
folder and right-click inside it. Choose Git GUI from the contextual menu. A dialog box will pop up as shown in the following screenshot:

Git GUI is not my preferred GUI tool, but you have it for free when installing Git. So, let's use it for the moment.
Go to Repository | Visualize All Branch History. A new window will open, and you will see the status of our current branches, as shown in the following screenshot:

We do not have the time to go into all the details here. As you become more confident with Git fundamentals, you will learn little by little all the things you see in the preceding picture.
If you don't want to leave the console to take a look, you could get a pretty output log even on the console. Try this articulated git log
command:
$git log --graph --decorate --pretty=oneline --abbrev-commit

This is a more compact view, but it is as clear as what we saw earlier.
Typing is boring – Git aliases
Before continuing, just a little warning. The last command we used is not the easiest thing to remember. To get around this nuisance, Git offers the possibility of creating your own commands, aliasing some of the verbose sequences.
To create an alias, we will use the git config
command. So, let's try to create a tree
alias for this command:
$ git config --global alias.tree 'log --graph --decorate --pretty=oneline --abbrev-commit'

So, the syntax to create aliases is as follows:
git config <level> alias.<alias name> '<your sequence of git commands>'
Using the --global
option, we told Git to insert this alias at the user level so that any other repository for my user account on this computer will have this command available. We have three levels where we can apply config personalization:
- Repository level configs are only available for the current repo
- Global configs are available for all the repos for the current user
- System configs are available for all the users/repositories
To create a repository user-specific config, we used the --global
option. For the system level, we will use the --system
option. If you don't specify any of these two options, the config will take effect only in the repository that you are in now.
Merging branches
Now that we finally got in touch with branches, let's assume that our work in the NewWork
branch is done and we want to bring it back to the master
branch.
To merge two branches, we have to move to the branch that contains the other branch commits. So, if we want to merge the NewWork
branch into the master
branch, we would first have to check out the master
branch. As seen earlier, to check out a branch we have to type the following command:
$ git checkout <branch name>;
If you want to check out the previous branch you were in, it's even simpler. Type this command:
$ git checkout –
With the git checkout –
command, you will move in the previous branch without having to type its name again as explained in the following screenshot:

Now, let's merge the NewWork
branch into master
using the git merge
command:
$ git merge NewWork
As you can see, merging is quite simple. With the git merge <branch to merge>
command, you can merge all the modifications in a branch into the actual branch as shown in the following screenshot:

When we read console messages, we see that Git is telling us something interesting. Let's take a look.
When Git says Updating 986a6dc..a0c7d61
, it is telling us that it is updating pointers. So now, we will have master
, NewWork
, and HEAD
all pointing to the same commit:

Fast-forward
is a concept that we will cover soon. When we tell Git to not apply this feature, in brief, this fast-forward feature (enabled by default) permits us to merge commits from different branches, as they were done subsequently in the same branch, obtaining a less-pronged repository.
Last, but not least, we have a complete report of what files are added, deleted, or modified. In our case, we had just one change (an insertion) and nothing else. When something is added, Git uses a green plus symbol +
. When a deletion happens, Git uses a red dash symbol -
.
Merge is not the end of the branch
This is a concept that sometimes raises some trouble. To avoid this, we will have a quick glimpse of it. You don't have to wait for the work to be done before merging another branch into your branch. Similarly, you don't have to think about merging as the last thing you will do before cutting off the other branch on which you worked.
On the contrary, it's better if you merge frequently from branches you depend on, because doing it after weeks or months can become a nightmare: too many changes in the same files, too many additions or deletions. Don't make a habit of this!
Exercises
To understand some common merging scenarios, you can try to resolve these small exercises.
Exercise 2.1
In this exercise we will learn how Git can handle automatically file modifications when they are not related to the same lines of text.
What you will learn
Git is able to automerge modifications on the same files.
Scenario
- You are in a new repository located in
C:\Repos\Exercises\Ch2-1
. - You have a
master
branch with two previous commits: the first commit with afile1.txt
file and the second commit with afile2.txt
file. - After the second commit, you created a new branch called
File2Split
. You realized thatfile2.txt
is too big, and you want to split its content by creating a newfile2a.txt
file. Do it, and then commit the modifications.
Results
Merging back File2Split
in the master
branch is a piece of cake. Git takes care of deletion in file2.txt
without spotting your conflicts.
Exercise 2.2
In this exercise we will learn how to resolve conflicts when Git cannot merge files automatically.
What you will learn
Git will result in conflicts if automerging is not possible.
Scenario
- You are in the same repository used earlier,
C:\Repos\Exercises\Ch2-1
. - On the
master
branch, you add thefile3.txt
file and commit it. - Then, you realize that it is better to create a new branch to work on
file3.txt
, so you create theFile3Work
branch. You move in this branch, and you start to work on it, committing modifications. - The day after, you accidentally move to the
master
branch and make some modifications on thefile3.txt
file, committing it. - Then, you try to merge it.
Results
Merging the File3Work
branch in master
gives rise to some conflicts. You have to solve them manually and then commit the merged modifications.
Deal with branches' modifications
As mentioned earlier, if you come from SVN at this point, you would be a little confused. You don't "physically have on the disk" all the branches checked out on different folders. Because of this, you cannot easily differentiate two branches to take into account what a merge will cost in terms of conflicts to resolve.
Well, for the first problem, there is not an SVN-like solution. However, if you really want to differentiate two checked out branches, you could copy the working directory in a temp
folder and check out the other branch. This is just a workaround, but the first time can be a less traumatic way to manage the mental shift Git applies in this field.
Diffing branches
If you want to do it in a more Git-like way, you could use the git diff
command. Let's give it a try by performing the following steps:
- Open
C:\Repos\MyFirstRepo
and switch to themaster
branch. - Add some text to the existing
NewFile.txt
, and then save it. - Add a
NewMasterFiles.txt
file with some text within it. At the end, add both files to the index and then commit them, as shown in the following screenshot:
Now, try to have a look at the differences between the master
and NewWork
repositories. Finding out the difference between the two branches is easy with the git diff
command:
$ git diff master..NewWork
The syntax is simple: git diff <source branch>..<target branch>
. The result, instead, is not probably the clearest thing you have ever seen:

However, with a little imagination, you can understand that the differences are described from the point of view of the NewWork
branch. Git is telling us that some things on master
(NewFile.txt
modifications and NewMasterFile.txt
) are not present in the NewWork
branch.
If we change the point of view, the messages change to those shown in the following screenshot:

Note
To better understand these messages, you can take a look at the diff output at http://en.wikipedia.org/wiki/Diff_utility.
Another way to check differences is to use git log
:
$ git log NewWork..master
This command lets you see commits that differ from the NewWork
branch to the master
branch.
There is even a git shortlog
command to give you a more compact view, as shown in the following screenshot:

Using a visual diff tool
All these commands are useful for short change history. However, if you have a more long change list to scroll, things would quickly become complicated.
Git lets you use an external diff tool of choice. On other platforms (for example, Linux or Mac), a diff tool is usually present and configured, while on the Windows platform, it is generally not present.
To check this, type this command:
$ git mergetool
If you see a message like this, you would probably have to set your preferred tool:

Resolving merge conflicts
As we have seen, merging branches is not a difficult task. However, in real-life scenarios, things are not that easy. We have conflicts, modifications on both branches, and other weird things to fight. In this section, we will take a look at some of them. However, first, remember one important thing: it needs a little bit of discipline to make the most of Git.
You have to avoid at least two things:
- Working hard on the same files on different branches
- Rarely merging branches
Edit collisions
This is the most common kind of conflict: someone edited the same line in the same file on different branches, so Git can't auto merge them for you. When this happens, Git writes special conflict markers to the affected areas of the file. At this point, we have to manually solve the situation, editing that area to fit our needs.
Let's try this by performing the following steps:
- Open your repository located in
C:\Repos\MyRepos
. - Switch to the
NewWork
branch and editNewFile.txt
by modifying the first lineAdded some text to the existing NewFile
inText has been modified
. - Add and commit the modification.
- Switch back to
master
and merge theNewWork
branch.
As you can see, Git highlighted the conflict. A conflict-marked area begins with <<<<<<<
and ends with >>>>>>>
. The two conflicting blocks themselves are divided by a sequence of =======
. To solve the conflict, you have to manually edit the file, deciding what to maintain, edit, or delete. After that, remove the conflict markers and commit changes to mark the conflict as resolved.

Once you resolve the conflicts, you are ready to add
and commit
:

Merge done, congratulations!
Resolving a removed file conflict
Removed file conflicts occur when you edit a file in a branch and another person deletes that file in their branch. Git does not know if you want to keep the edited file or delete it, so you have to take the decision. This example will show you how to resolve this both ways.
Keeping the edited file
Try again using NewFile.txt
. Remove it from the NewWork
branch and then modify it in master
:

After that, merge NewWork
in the master
branch. As said earlier, Git spots a conflict. Add NewFile.txt
again in the master
branch and commit it to fix the problem:

When resolving merge conflicts, try to commit without specifying a message, using only the git commit
command. Git will open the Vim editor, suggesting a default merge message:

This can be useful to spot merge commits looking at the repository history in the future.
Resolving conflicts by removing the file
If you agree with the deletion of the file in the other branch, instead of adding it again, remove it from your branch. So, use the git rm NewFile.txt
command even in the master
branch and then commit to mark the conflict resolved.
Stashing
Working of different features in parallel does not make a developer happy, but sometimes it happens. So, at a certain point, we have to break the work on a branch and switch to another one. However, sometimes, we have some modifications that are not ready to be committed, because they are partial, inconsistent, or even won't compile. In this situation, Git prevents you from switching to another branch. You can only switch from one branch to another if you are in a clean state:

To quickly resolve this situation, we can stash the modifications, putting them into a sort of box, ready to be unboxed at a later time.
Stashing is as simple as typing the git stash
command. A default description will be added to your stash, and then modifications will be reverted to get back in a clean state:

To list actual stashes, you can use the list
subcommand:

Once you have done the other work, you can go back to the previous branch and apply the stash to get back to the previous "work in progress" situation:

What we have seen is the most common scenario and most used approach, but stashing is a powerful Git tool. You can have multiple stashes, apply a stash to a different branch, or reverse apply a stash. You can even create a branch starting from a stash. You can learn more about this on your own.
Summary
In this chapter, you learned the core concepts of Git: how it handles files and folders, how to include or exclude files in commits that we do, and how commits compose a Git repository.
Next, we explored the most used and powerful feature of Git, its ability to manage multiple parallel branches. For a developer, this is the feature that saves you time and headache while working on different parts of your project. This feature lets you and your colleagues collaborate without conflicts.
At the end, we touched on Git's stashing ability, where you can freeze your current work without having to commit an unfinished change. This helps you develop good programmer habits, such as the one that tells you to not commit an unfinished change.
In the next chapter, we will complete our journey of Git fundamentals, exploring ways and techniques to collaborate with other people.
- FuelPHP Application Development Blueprints
- GraphQL學習指南
- 少年輕松趣編程:用Scratch創作自己的小游戲
- HTML5+CSS3網站設計教程
- Visual Basic程序設計與應用實踐教程
- Python編程實戰
- MySQL從入門到精通(軟件開發視頻大講堂)
- PHP編程基礎與實踐教程
- RubyMotion iOS Develoment Essentials
- Data Manipulation with R(Second Edition)
- Java語言程序設計實用教程(第2版)
- Enterprise Application Architecture with .NET Core
- Java核心技術速學版(第3版)
- Django 2.0 入門與實踐
- Learning Zimbra Server Essentials