Tree of Dragons II by surrealistguitaristFor those who use Git every day but feel insecure, the teamMail.ru Cloud Solutions has translated an article by front-end developer Shane Hudson . Here you will find some tricks and tips that can make it a little easier to work with Git, as well as a selection of articles and manuals of a more advanced level.Git appeared almost 15 years ago. During this time, he went from an underdog to an invincible champion. Today, new projects often start with a team git init
. Undoubtedly, this is an important tool that many of us use daily, but often it resembles magic - bright, but dangerous.Many articles have been published on Habr, how to get started with Git, how Git works under the hood , and descriptions of the best branching strategies. Here, the author focused on how to simplify work with Git.We put things in order
Git's point is to save your work, switch context - and do something else. This can be a backup of the code or the ability to asynchronously develop several different functions. It would be terrible to throw away the second version only because an error was found in the first. It is no less embarrassing to save files with names like v1_final_bug_fixed. As you know, this leads to a complete mess.We all know that life becomes much easier when our updates are neatly laid out on Git branches that you can share with colleagues. But often situations arise when you change the context, then go back - and you cannot find the right branch. Was there a commit at all? Maybe he's hidden? Maybe the commit didn’t pass, now everyone has gone to the wrong branch, and everything is bad, and I am doing terribly bad work! Yes, everyone was there and felt such doubts. There are ways to deal with this situation.Sort branches by date
Sorting by date shows all of your local branches, starting from the last. Pretty commonplace, but it helped me many times:
git branch --sort=-committerdate
Previous thread
What if you didn’t commit, switch the branch, and then want to return to the previous one? You can probably find it in the list of branches if you have some idea of its name. But what if it's not a branch, but a detached HEAD
specific commit?It turns out there is a simple way out:
git checkout -
The operator -
is a shorthand for syntax @{-1}
that allows you to switch to any number of checkouts back. So if, for example, you created a branch feature/thing-a
, then feature/thing-b
, and then bugfix/thing-c
, the parameter @{-2}
will return you to feature/thing-a
:
git checkout @{-N}
Show information about all branches
The flag v
shows a list of all branches with the last commit identifier and message. The double vv
will also show the remote upstream branches, followed by the local branches:
git branch -vv
Find file
We all fell into this situation: somehow it turned out that one file was left in the wrong branch. What to do? Redo all work or copy code from one branch to another? No, fortunately, there is a way to find a specific file.The method is a bit strange, given that git checkout -
takes you to the previous branch. In general, if you specify --
after the branch name in checkout, this will allow you to specify the specific file that you are looking for. You won’t guess such a function without a hint, but it is very convenient if you know:git checkout feature/my-other-branch -- thefile.txt
Clear status
Tomasz Lacoma tweeted about reducing the issuance git status
with the help of flags -sb
and added: "For many years I have been using Git, but no one has told me about this." It's not just about finding lost files. There are times when simplifying the issue makes it easier to view changes.Most Git commands have these flags, so you should learn how to use them to customize your workflow:
git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
another-file
my-new-file
git status -sb
M README.md
?? another-file
?? my-new-file
Whole story
There are times when something went completely wrong, for example, you accidentally discarded staged (preparatory) changes before committing them. If it git log
does not allow you to return to the previous state and none of the above tips helps, that is git reflog
.All your actions in Git that change the contents by reference HEAD@{}
(for example push/pull/branch/checkout/commit
) fall into the reflog (reference log). In fact, this is the story of all your actions, no matter which branch you are in. This is the difference with git log
, which shows the changes for a particular branch.You can do git show
with the commit ID - and see the specific change. If this is what you were looking for, it will git checkout
transfer you to the desired branch or even allow you to select a specific file, as shown above:
git reflog --all
git show HEAD@{2}
git checkout HEAD@{2}
Prep files that missed the commit
In extreme cases, if it git reflog
does not help to get your files back (for example, you ran a hard reset with intermediate files), there is one more trick.Each change is stored inside objects .git/objects
that are filled with files in the active project, so it’s almost impossible to figure it out. However, there is a Git command called git fsck
, which is used to check the integrity (presence of damaged files) in the repository. We can use it with a flag --lost-found
to search for all files not related to a commit. Such files are called "dangling blob".This command also allows you to find "hanging trees" and "hanging commits." If you want, you can use the flag --dangling
, but the advantage--lost-found
in that it extracts all the relevant files into a folder .git/lost-found
. Most likely, in an active project you will have many such “hanging” files. Git has a garbage disposal command that runs regularly and removes them.Thus, it --lost-found
will show all the files and the time / date of creation, which greatly facilitates the search. Note that each separate file will still be separate, that is, you cannot use checkout. Also, all files will have incomprehensible names (hash), so you have to copy the necessary files to another location:
git fsck --lost-found
ls -lah .git/lost-found/other/
cp .git/lost-found/other/73f60804ac20d5e417783a324517eba600976d30 index.html
Git in team work
Using Git alone is one thing, but when you work in a team of people, usually with completely different experiences, skills and tools, Git can be a blessing or a curse. This is a powerful tool for sharing the same code base, conducting a code review and monitoring the progress of the entire team. At the same time, all employees are required to have a common understanding of how to use it in team work. Regardless of what it is about: the convention of naming the branches, formatting the accompanying message in the commit, or choosing which files to include in the commit, it is important to ensure good communication and agree on how to use this tool.It is always important to ensure the simplicity of onboarding for beginners and to think about what will happen if they start making commits without knowing the principles and conventions adopted by the company. This is not the end of the world, but it can cause some confusion and take time to return to a coordinated approach.This section contains a few recommendations on how to integrate the accepted agreements directly into the repository itself, automate and issue the maximum number of tasks in declarations. In the ideal case, any new employee almost immediately starts working in the same style as the rest of the team.The same line endings
By default, Windows uses DOS line endings \r\n
(CRLF), while Mac and Linux use UNIX line endings \n
(LF), while older versions of Mac use \r
(CR). Thus, as the team grows, the problem of incompatible line endings becomes more likely. This is inconvenient, they (usually) do not break the code, but because of them, commits and pool requests show various irrelevant changes. Often people simply ignore them, because it’s quite troublesome to walk around and change all the wrong line endings.There is a solution - you can ask all team members to configure their local configurations for automatic line completion:
git config core.eol lf
git config core.autocrlf input
Of course, you need to sign up for this convention and a beginner, which is easy to forget. How to do this for the whole team? According to the algorithm of work, Git checks for the presence of a configuration file in the .git / config repository, then checks the system-wide configuration of user in ~/.gitconfig
, and then checks the global configuration in /etc/gitconfig
.All this is good, but it turns out that none of these configuration files can be installed through the repository itself. You can add repository-specific configurations, but they will not extend to other team members.However, there is a file that is actually committed to the repository. It is called .gitattributes . By default, you don’t have it, so create a new file and save it as*.gitattributes*
. It sets attributes for each file. For example, you can force git diff to use exif headers from image files instead of trying to calculate the difference in binary files. In this case, we can use a wildcard so that the setting works for all files, acting, in fact, as a common configuration file for the entire command:
* text=auto
Auto hide
It is customary to add compiled files (such as node_modules/
) to .gitignore so that they are stored locally and not uploaded to the repository. However, sometimes you still want to upload the file, but do not want to meet it later each time in the pool request.In this situation (at least on GitHub), you can add marked paths to .gitattributes linguist-generated
and make sure that .gitattributes is in the root folder of the repository. This will hide the files in the pool request. They will be “minimized”: you can still see the fact of the change, but without the full code.Everything that reduces stress and cognitive load in the code review process improves its quality and reduces time.For example, you want to add resource files (asset) to the repository, but you are not going to modify and track them later, so you can add the following line to the file with attributes:*.asset linguist-generated
Use git blame more often
Harry Roberts 's article “Little Things I Like To Do With Git” recommends git blame
(assign git praise
translation ) to assign an alias (translating from translation “English”) to feel this team as a positive action. Of course, renaming does not change the behavior of the team. But whenever the discussion comes up with the use of a function git blame
, everyone gets tense, and of course I do too. It is only natural to perceive the word blame (guilt) as something negative ... but this is completely wrong!A powerful function git blame
(or git praise
, if you want) shows who was the last to work with this code. We are not going to blame or praise him, but just want to clarify the situation. It becomes clearer which questions to ask and to whom, which saves time.It should be presented git blame
not only as something good, but also as a means of communication that helps the entire team to reduce chaos and not waste time figuring out who knows what. Some IDEs, such as Visual Studio, activate this feature as annotations. For each function, you instantly see who last changed it (and, therefore, with whom to talk about it).Analog git blame for missing files
Recently, I saw a developer on our team trying to figure out who deleted a file, when, and why. It seems like it can help here git blame
, but it works with the lines in the file and is useless if the file is missing.However, there is another solution. Old faithful git log
. If you look at the log without arguments, you will see a long list of all changes in the current branch. You can add a commit identifier to see the log of this particular commit, but if you specify --
(which we used earlier to target a specific file), you can get a log for a file - even one that no longer exists:
git log -- missing_file.txt
Commit Message Template
Commit messages often need to be improved. Sooner or later, the developers in the team come to this conclusion. There are many ways to improve. For example, you can refer to bug identifiers from an internal project management tool, or perhaps encourage writing at least some text instead of a blank message.This command needs to be run manually every time someone clones the repository, since configuration files are not committed to the repository. However, it is convenient because you can create a common file with any name that acts as a commit message template:
git config commit.template ./template-file
Git for automation
Git is a powerful automation tool. This is not immediately obvious, but think for yourself: he sees all your activity in the repository - plus the activity of other participants - and he has a lot of information that can be very useful.Git hooks
Quite often, you see that team members perform repetitive tasks while working. This can be a test of passing tests and linter before sending a branch to the server (hook before sending) or a forced strategy for naming branches (hook before committing). On this subject, Konstantinos Lamonis wrote an article in the Smashing Magazine entitled “How to Simplify Workflow Using Git Hooks” .Manual automation
One of the key automation features in Git is git bisect. Many have heard of it, but few use it. The bottom line is processing the Git tree (commit history) and finding where the error is entered.The easiest way to do this is by hand. You start git bisect start
, set the identifiers of good and bad commits (where there is no bug and where there is a bug), then execute git bisect good
or git bisect bad
for each commit.This is a more powerful feature than it seems at first glance, because it does not run the Git log linearly, which could be done manually as an iterative process. Instead, it uses a binary search that effectively passes through commits with the least number of steps:
git bisect start
git bisect good c5ba734
git bisect bad 6c093f4
git bisect bad
git bisect good
git bisect reset
git bisect reset HEAD
git bisect reset <commit ID>
Moving On: Scientific Automation
In his scientific debugging report, Stuart Halloway explained how to use the command git bisect
to automate debugging.He focuses on Clojure, but we don’t need to know this language to benefit from his talk.Git bisect is partly scientific automation. You write a small program that will test something, and Git jumps back and forth, cutting the world in half with each jump, until it finds the border at which your test changes state.
Stuart Halloway
At first it git bisect
may seem like an interesting and pretty cool feature, but in the end it is not very useful. Stewart’s performance to a large extent shows that it is actually counterproductive to debug as we are used to. If you instead focus on empirical facts, whether the test passes or not, then you can run it on all commits, starting with the working version, and reduce the feeling of “wandering in the dark” that we are used to.So how do we automategit bisect
? You can pass it a script for each corresponding commit. Earlier, I said that you can manually run the script at each step of bisect, but if you pass a command to run, it will automatically run the script at each step. It can be a script specifically for debugging this specific problem or a test (modular, functional, integration, any type of test). Thus, you can write a test to verify that the regression does not repeat, and run this test on previous commits:
git bisect start
git bisect good c5ba734
git bisect bad 6c093f4
git bisect run ./test-bug
git bisect run jest
On every past commit
One of the strengths git bisect
is the effective use of binary search to bypass all events in history in a non-linear way. But sometimes a linear bypass is needed. You can write a script that reads the Git log and cycles through the code on every commit. But there is a friend, who will do it for you: git rebase
.Kamran Ahmed in a tweet written as rebase
is, what commit does not pass the test:Find a commit that fails the test:
$ git rebase -i --exec "yarn test" d294ae9
The command runs yarn test on all commits between d294ae9 and HEAD and stops at the commit where the test crashes.
We have already considered git bisect
for this task, which may be more efficient, but in this case we are not limited to one use case.There is a place for creativity. Perhaps you want to generate a report on how the code has changed over time (or show the history of tests), and just parsing the Git log is not enough. Maybe this is not the most useful trick in this article, but it is interesting and shows a task, the reality of which we could not believe before:
git rebase -i --exec ./my-script
A selection of articles and manuals to help you get deeper into Git
In such an article, it is impossible to delve into the topic, otherwise the whole book will turn out. I chose some small tricks that even experienced users might not know about. But Git has much more features: from basic functions to complex scripts, precise configurations and console integration. Therefore, here are some resources that may be of interest to you:- Explorer git . An interactive site that helps you easily understand how to achieve what you want.
- Dang it git! . Each of us at some point can get lost in Git and does not know how to solve any problem. This site provides solutions to many of the most common problems.
- Pro git . This free book is an invaluable resource for understanding Git.
- Git Docs. — . , Git Docs, Git (, man git-commit) Git .
- Thoughtbot. Git Thoughtbot .
- Git. Git.
- Git. , … . Git, .
- Git: from beginner to advanced level . Mike Ritmüller has written this useful article, which is ideal for novice Git users.
- Little things I love to do with Git . It was this article by Harry Roberts that made me realize how many possibilities still lurk in Git, apart from moving code across branches.
- Atlassian Advanced Git Guides . These tutorials detail many of the topics mentioned in this article.
- Git cheat sheet on Github . It's always convenient to have a good cheat sheet for tools like Git.
- Git reduction . This article details various Git command flags and recommends many aliases.
But what else can you read :- Git. №1: , .git
- Git. №2: rebase.
- .