📜 ⬆️ ⬇️

Git in practice

There is a wonderful book Pro Git, which describes in detail all the commands and features of the gita. But after reading it, many still have a misunderstanding of how to use all this in practice. In particular, programmers of different levels often have questions about how to work with branches in Git, when to start them and how to merge with each other. Sometimes I came across very "original" and unreasonably complicated schemes of working with git. While in the community of programmers has already formed a scheme of work with git and branches in it. In this article I want to give a brief overview of the main points when working with Git, and describe the “classical” workflow with branches. Much of what is described in this article will be true for other version control systems.

This article may be useful for programmers who are just starting to learn Git, or some other version control system. For experienced programmers, this article will seem very simple and banal.

First, let's understand what a branch and commit are.

Commit


We can say that a commit is the main object in any version control system. It contains a description of the changes that the user makes to the application code. In Git, a commit consists of several so-called objects. For ease of understanding, we can assume that commits are a simply linked list consisting of objects that contain modified files, and a link to the previous commit.
')


A commit has other properties. For example, commit date, author, comment to commit, etc.
As a comment, they usually indicate the changes that this commit makes to the code, or the name of the task that it solves.

Git is a distributed version control system. This means that each project participant has its own copy of the repository, which is located in the “.git” folder, which is located in the project root. It is in this folder that all commits and other Git objects are stored. When you work with Git, it in turn works with this folder.

Creating a new repository is very simple, it is done by the team.

git init

So you get a new empty repository. If you want to join the development of an existing project, then you will need to copy this repository to your local folder from a remote repository. This is done like this:

git clone <url >

After that, a .git directory will appear in the current folder, which will contain a copy of the remote repository.

There are several main areas where code is located.


In general, working with git looks like this: you change files in your working directory, then add these changes to the staging area using the command

git add </>

You can use masks with an asterisk.
Then you commit to your local repository.

git commit –m “ ”

When kommitov to collect enough that it was possible to share them, you execute a command

git push

Then your commits go to the remote repository.

If you need to receive changes from a remote repository, then you need to run the command

git pull

After that, the changes that were sent by other programmers will appear in your local repository.

The code in the project workspace is formed by applying those changes that are contained in commits. Each commit has its own name, which is the result of the hash function sha-1 from the contents of the commit itself.

You can view commits using the command

git log

The default response format of this command is not very convenient. Here such a command will display the answer in a more readable form.

git log --pretty=format:"%H [%cd]: %an - %s" --graph --date=format:%c

To finish viewing you need to press the q key
You can see what is in the working directory and staging area with the command

git status

The working directory can be switched to the previous state by executing the command

git checkout <hash >

Just before doing this, run git status and make sure you don’t have any local or unchanged changes. Otherwise, Git will not understand how to switch. git status will tell you what can be done with local changes so that you can switch. This rule should be followed in all other switchings of the working area.

Branch


A branch in Git is a moving pointer to one of the commits. Usually a branch points to the last commit in a chain of commits. The branch originates from a single commit. Visually, this can be represented like this.



You can make a new branch and switch to it by executing the commands

git pull
git checkout –b < >


Just make a branch, without switching to it, you can command

git branch < >

switch to branch

git checkout < >

It is important to understand that the branch originates not from the branch, but from the last commit that is in the branch in which you were located.

A branch usually ends with a special merge commit , which says that the branch needs to be merged with some other branch. A merge commit contains two links to two commits that are combined into one branch.



There is another situation when merging branches in which merge can occur without merge commit. The fact is that if in one of the branches there are no changes, then the need for a merge commit with two ancestors disappears. In this case, when merging branches, Git will simply make a note that the commits of the branch with which this branch was merged will go on. Such a merge scheme is called fast-forward merge, visually this can be represented as follows.



In all these cases, after a branch merges with another branch, all commits made in it fall into the branch with which it was merged. It is also important to understand that merge is not a bidirectional operation. If you merge a task branch into the master branch, then the code that was in the task branch will appear in the master branch, and no new code from the master branch will appear in the task branch. If you want this to happen, you need to merge the master branch into the task branch.
To transfer one branch to another you first need to switch to the branch you want to merge into.

git checkout < >

Then get the latest changes made in this thread by running

git pull

Then execute the command

git merge < >

This is how work with branches looks in general.

Please note that before starting a new branch you need to perform git pull. This is done for several reasons.


Popular branching schemes in Git



Now you can describe the popular schemes of working with branches in the gita.

Branches are needed so that programmers can work together on a project and not interfere with each other. When creating a project, Git creates a basic branch. It is called the master branch. It is considered a central branch, i.e. it contains the main application code.

The classic scheme of working with branches


Usually, before starting to solve a problem, the programmer starts a new branch from the last working commit of the master branch and solves the problem in this new branch. During the solution, he makes a series of commits, then tests the code directly in the branch of the problem. And after the problem is solved, they do the merge back to the master branch. Such a scheme of work is often used with unit tests and automated deploem. If the unit tests cover the whole code, then you can configure the deployment so that first all the tests in the task branch will be run. And after that, if they are successful, merge and deployment will occur. With this scheme, you can achieve full automation during testing and deployment.

Nominal branch


Inexperienced programmers give birth to their own branch and always work in it. They solve one task at a time, and when they finish solving one of the tasks, they make a new Pull request via the Web interface (more on this later). The disadvantage of this approach is that only one task can be solved this way and one cannot quickly switch to solving another task. Another drawback is that the branches will diverge more and more over time and the code in the programmer’s branch will sooner or later become obsolete with respect to the master of the branch and will have to be updated. To do this, you can either merge the master branch into the programmer's branch, or start a new branch for this programmer from the last working state into the master branch. True, by the time this happens, the programmer can already master the git sufficiently to switch to the “classical” scheme of work. Thus, this scheme is the place to be for inexperienced Git users.

Diagram with dev branch


The other scheme is very similar to the classical one, only there is a development branch in addition to the master branch, which is deployed to the test server. This branch is usually called dev. The scheme of work with this. A programmer, before performing a new task, gets a branch for it from the last working state to the master branch. When he finishes work on the task, he merges the branch of the task into the dev branch himself. After that, jointly, the task is tested on a test server along with the rest of the tasks. If there are errors, then the task is refined in the same branch and re-merged with the dev branch. When the testing of the task ends, the TASK TAG is merged with the master branch. It is important to note that in this scheme of working with the master branch, you need to merge the branch of the task, and not the dev branch. After all, the dev branch will contain changes made not only in this task, but also in others and not all of these changes may turn out to be working. The master branch and the dev branch will diverge over time, so with such a scheme of work, a new dev branch from the last working state of the master branch is periodically started. The disadvantage of this approach is redundancy, compared with the classical scheme. This branching scheme is often used if there are no automated tests in the project and all testing is done manually on the development server.

It should also be noted that these work schemes can be combined with each other, if there is any need for this.

Pull requests


There is confusion with this concept. The fact is that in Git there are two completely different things that can be called a pull request. One of them is the git pull console command. The other is the button in the repository web interface. On github.com, it looks like this



About this button and will be discussed further.

If the programmer is experienced and responsible enough, he usually merges his code into the master branch himself. Otherwise, the programmer makes a so-called pull request. Pull request is essentially a request for permission to make a merge. Pull request can be done from the Git web interface, or using the request-pull git command. After the pull request is created, other participants can see this, view the code that the programmer is proposing to contribute to the project, and either approve this code or not. Merge through pull requests has its pros and cons. The downside is that for a close team of experienced programmers such an approach would be superfluous. This will only slow down the work and bring it into the shades of bureaucracy.

On the other hand, if there are not experienced programmers in the project who can break the code, then Pull requests can help avoid errors, and quickly train these programmers by observing what changes they propose to make to the code.

Similarly, pull queries are suitable for a wide community of open source programmers. In this case, one cannot say in advance something about the competence of such developers and what they want to change in the code.

Conflicts


Conflicts arise when branches are merged if in these branches the same line of code was changed differently. Then it turns out that Git cannot decide which of the changes to apply, and he suggests manually solving this situation. This slows down the work with the code in the project. This can be avoided by various methods. For example, you can distribute tasks so that related tasks are not performed simultaneously by different programmers.
Another way to avoid this is to agree on a particular style of code. Then programmers will not change the formatting of the code and the likelihood that they will change the same line will be lower.

Another good advice that will help you avoid conflicts when working in a team is to make minimal changes to the code when solving problems. The fewer lines you have changed, the less likely you are to change the same line as another programmer in another task.

After the master branch reaches a state that can be considered stable, it is tagged with a version of this state. This is what is called the program version.
This is done like this

git tag -a v1.0

To transfer branches to a remote repository, you need to run the command

git push –tags

Tags are also convenient because you can easily switch to the state of the code tagged. This is done using the same command.

git checkout < >

Various deployment and automated assembly systems use tags to identify the state that needs to be fixed or assembled. This is done because if we collect or deploy the code of the latest version, then there is a risk that some other programmer will make some changes to the master branch at that moment, and we will collect not what we wanted. In addition, it will be easier to switch between working and verified project states.

If you adhere to these rules and the “classical” scheme of working with branches, then it will be easier for you to integrate your Git with other systems. For example, with a continuous integration system or with a package repository, such as packagist.org. Usually, third-party solutions and any extensions are designed specifically for such a scheme of working with git, and if you immediately start doing everything correctly, then this can be a big plus for you in the future.

This is an overview of the main points when working with Git. If you want to learn more about Git, then I would advise you to read the Pro Git book. Here it is .

In this article, a simplified scheme for presenting commits has been given. But before writing it, I decided to figure out how exactly the commits are stored on the disk. If you are also interested in this question, then you can read about it here .

Source: https://habr.com/ru/post/342116/


All Articles