Advanced use of the Geeta or how to retire six months earlier?

Advanced use of the Geeta or how to retire six months earlier?
 
I do not know what programming language you write, but I'm sure that you use Git in development. Tools for tracking development are becoming more and more, but even the smallest test project, I invariably start with the team git init . And during the working day I dial an average of 80 more teams, referring to this version control system.
 

I spent a bunch of nerves when I began to re-learn the ten-finger method of printing. In the end, it was the right decision to improve the personal workflow. Among the next on the importance of optimizations is the in-depth development of the Gita.


 

The Habr has written many articles about the Gita, but they do not go beyond the official documentation, and authors offer cribs to simplify the work. I am sure that it is necessary to study the Git on specific examples of problems, but to increase the effectiveness of working with it - by standardized means.


 

Who will benefit from this article?


 

Have you already mastered the Gita gentlemen's set and are ready to move on? There are 2 ways:


 
  1.  
  2. Learn abbreviated commands - aliases. They are almost always composed mnemonic and easy to remember. To forget the originals of teams is problematic, I easily type them when it is required. Plus, I do not lose my mind by checking something in the Gita while writing the code.  
  3. Learn about additional flags for teams, as well as their association among themselves. I understand that someone hates cuts. For you, too, there is an interesting material in the article - how to increase the usefulness and convenience of the output of commands, as well as how to solve not the most trivial, but often encountered in practice, tasks .  

 

Devote to the experiments described in the article a couple of hours today, and save by approximate calculations half a year of working life.


 

Welcome to the cut!

Linux , and for Mac , and even for Windows .
 

Installation Zsh and Oh My Zsh


 

Install Zsh and Oh My Zsh according to the instructions with one command:


 
    # macOS
brew install zsh zsh-completions && sh -c "$ (curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
# Ubuntu, Debian,
apt install zsh && sh -c "$ (curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

 

Since the problem is to optimize the interaction with the Git , we add to Zsh a couple of plugins. Open the file ~ /.zshrc and add to the list plugins :


 
    plugins = (git gitfast)    

 

Total:


 
  •  
  • git - a set of aliases and auxiliary functions;  
  • gitfast - Improved autocompletion for the Geetha.  

 

Installation tig


 

And the final touch is the installation of the console utility tig :


 
    # macOS
brew install tig
# Ubuntu, Debian,
# https://jonas.github.io/tig/INSTALL.html

 

About it we'll talk further.


 

Hit in practice


 

Dealing with the Geeth best on examples of solving specific problems. Next, consider the tasks from daily practice and options for their convenient solution. To do this, consider a repository with text files.


 
In yellow blocks, the main alias for solving the problem from the section is indicated. Learn only it, and leave the rest for general development.

 

Check the status of the working directory


 

Let's start with the most basic thing. We have worked a little and now let's see what happens in the working directory:


 
    $ git status
On branch master
Changes to be committed:
(use "git reset HEAD " to unstage)
new file: e.md
Changes not staged for commit:
(use "git add " to update what will be committed)
(use "git checkout - " to discard changes in working directory)
modified: b.md
Untracked files:
(use "git add " to include in what will be committed)
d.md

 

The current state of all files is described in great detail, additional manuals for action are given. It is very useful in the first stages of using the Geetha, but for everyday work it is very much too much. Let's reduce the noise level with additional keys:


 
    $ git status -sb
## master
M b.md
A e.md
?? d.md

 

Yeah, we're in the branch. master , changed the file b.md ( ? M-odified ) And created two files, adding the first one to the Geeta index ( .A-dded ), And the second left outside the index ( ?? ). Briefly and clearly.


 

It remains to optimize the infinite input of this command alias « g it s tatus with b ranch " :


 
Show the reduced status of the working directory
 
 
    $ gsb # git status -sb    

 

 

Create a commit


 

We continue.


 

Of course, you know how to create commits. But let's try to optimize the solution of this simple task. We add all changes to the index with alias « g it a dd a lt; :


 
    $ gaa # git add --all    

 

We check that the index got exactly what we need with the help of alias « g it d iff ca ched " :


 
    $ gdca # git diff --cached
diff --git a /b.md b /b.md
index 698d533cf???r3r31592. --- a /b.md
+++ b /b.md
@@ -1.3 +1.3 @@
# Beta
-Next step.
+ Next step really hard.
diff --git a /d.md b /d.md
new file mode 100644
index 00000009e3752e
--- /dev /null
+++ b /d.md
@@ -?0 +?3 @@
+ # Delta
+
+ Body of article.

 

Hmm, one commit should include changes that solve a single task. Here, the changes of both files are not connected in any way. Let's exclude the file for now. d.md from the index by alias « g it r eset u ndo & quot; :


 
    $ gru d.md # git reset - d.md    

 

And create a commit alias « g it c ommit » :


 
    $ gc # git commit    

 

We write the name of the commit and save it. And then create another commit for the file d.md more familiar command with the help of alias « g it c ommit m e s sa g e " :


 
    $ gaa # Already familiar alias
$ gcmsg "Add new file" # git commit -m "Add new file"

 

And we can


 


commit the modified files from the index with one command:


 
    $ gcam "Add changes" # git commit -a -m "Add changes"    

 


watch the changes in words instead of lines (very useful when working with text):


 
    $ gdw # git diff --word-diff    

 


add files in parts (very useful when you need to add to the commit only part of the changes from the file):


 
    $ gapa # git add --patch    

 


add only files already under the supervision of the Gita to the index:


 
    $ gau # git add --update    

 

Total:


 
Add to index /Create a commit
 
 
    $ ga # git add
$ gc # git commit

 

 

Correct the commit


 

The name of the last commit does not explain the changes we made. Let's reformulate:


 
    $ gc! # git commit -v --amend    

 

And in the opened text editor let's call it more clearly: "Add Delta article" . I'm sure you never use the key. -v , although when editing the description of the commit, it shows all the changes made, which helps to better navigate.


 

And we can


 


make changes to the commit file, but do not touch the description:


 
    $ gcn! # git commit -v --no-edit --amend    

 


make all changes to the files immediately in the commit, without first adding to the index:


 
    $ gca! # git commit -v -a --amend    

 


combine the two previous commands:


 
    $ gcan! # git commit -v -a --no-edit --amend    

 

Well, it's important to note again that instead of typing a full regularly used command git commit -v --amend , we write only three characters:


 
Edit the last commit
 
 
    $ gc! # git commit -v --amend    

 

 

We start working on the new feature


 

Create a new branch from the current alias « g it c heckout b ranch " :


 
    $ gcb erlang # git checkout --branch erlang    

 

Although no, better write an article about more modern language Elixir aliases « g it b ranch with the key m ove » (renaming in the Gita is done through move ):


 
    $ gb -m elixir # git branch -m elixir    

 

It would be logical to use alias gbmv , but it, unfortunately, has not yet been invented. A good option for a contribute.


 

We make changes to the repository and create a commit, as we already know how:


 
    $ echo "# Elixir is the power of Erlang with the grace of Ruby." > e.md
$ gaa && gcmsg "Add article about Elixir"

 

And remember:


 
Create a new branch
 
 
    $ gcb # git checkout --branch    

 

 

Merge the changes


 

Now add our new article about Elixir in master . First, switch to the main branch with alias « g it c heckout m aster » :


 
    $ gcm # git checkout master    

 

No seriously. One of the most commonly used commands in three easy-to-remember symbols. Now merjim changes the alias « g it m erge " :


 
    $ gm elixir # git merge elixir    

 

Oops, and in master someone has already made their changes. And instead of the beautiful linear history, which was adopted in our project, was created. hated merge commit.


 
Merge the branches
 
 
    $ gm # git merge    

 

 

Delete the last commit


 

Nothing wrong! You just need to delete the last commit and try to merge the changes again « g it r eset hh ard :


 
Delete the last commit
 
 
    $ grhh HEAD ~ # git reset --hard HEAD ~    

 

 

We resolve conflicts


 

The standard sequence of actions is checkout - rebase - merge To prepare a linear change history, the following sequence of aliases is executed:


 
    gco elixir # git checkout elixir
grbm # git rebase master
gcm # git checkout master
gm elixir # git merge elixir

 

All of them are so often used that they are already flying off their fingers, and doing such operations, there is no need to think about which set of letters to type. And do not forget that in Zsh You can supplement the names of branches with the key Tab .


 
Make a rebree
 
 
    $ grb # git rebase    

 

 

Sending changes to the server


 

First, add origin aliases « g it r emote a dd " :


 
    $ gra origin [email protected] /# git remote add origin [email protected] /  

 

And then we send the changes directly to the current branch of the repository (
? "gg" -doubled .g , At the beginning of the command indicates execution of the action in the current branch):


 
    $ ggpush # git push origin git_current_branch    

 

You can also


 


send the changes to the server with the installation of upstream aliases « g it p ush s et up stream :


 
    $ gpsup # git push --set-upstream origin $ (git_current_branch)    

 
Send changes to the server
 
 
    $ gp # git push    

 

 

We receive changes from the server


 

Work is in full swing. We managed to add a new article f.md in master , and our colleagues change article a.md and send this change to the server. This situation is also very simple:


 
    $ gup # git pull --rebase    

 

After that you can safely send changes to the server. The conflict is over.


 
Get changes from the server
 
 
    $ gl # git pull    

 

 

Remove the merged branches


 

So, we successfully poured into master several branches, including the branch. elixir from the preceding example. We do not need them any more. You can delete the alias « g it b ranch d elete a nother » :


 
    $ gbda # git branch --no-color --merged | command grep -vE "^ (* | s * (master | develop | dev) s * $)" | command xargs -n 1 git branch -d    

 

A very beautiful and cunning team. Usually I forget to clean up the branches that have lost their relevance and this elegant team is a real salvation. If you do not want to use the alias, just copy the full version of the command to your notes, and execute it as needed.


 

Create a temporary commit


 

Work on a new article h.md about Haskell is in full swing. Half is written and you need to get a response from a colleague. Without thinking twice, type alias « g it w ork i n p rogress » :


 
    $ gwip # git add -A; git rm $ (git ls-files --deleted) 2> /dev /null; git commit --no-verify -m "--wip--[skip ci]"    

 

And then a commit with the name is created. Work in Progress , skipping CI and deleting "extra" files. We send the branch to the server, talk about this colleague and wait for the review.


 

Then you can undo this commit and return the files to their original state:


 
    $ gunwip # git log -n 1 | grep -q -c "--wip--" && git reset HEAD ~ 1    

 

And to check up, whether there is in your branch WIP You can use the command:


 
    $ work_in_progress    

 

Team gwip - fairly reliable analogue stash , when you need to switch to the next branch. But in Zsh there are many aliases for itself. stash .


 
Add temporary commit /Reset temporary commit
 
 
    $ gwip
$ gunwip

 

 

Hide the changes


 

With this team you need to be careful. Files can be hidden, and then deleted with a careless action permanently, the good is reflog , in which you can try to find the lost work.


 

Let's hide the files we are working on by alias « g it st ash a lt; :


 
    $ gsta # git stash save    

 

And then return them back to aliases « g it st ash p op " :


 
    $ gstp # git stash pop    

 

Or the safer method « g it st ash a ll a pply " :


 
    $ gstaa # git stash apply    

 

You can also


 


to see what exactly we hid:


 
    gsts # git stash show --text    

 


use abbreviations for related commands:


 
    gstc # git stash clear
gstd # git stash drop
gstl # git stash list

 
Hide changes /Get changes
 
 
    $ gsta
$ gstaa

 

 

We are looking for a bug


 

Tool git-bisect , who repeatedly saved my life, also has its aliases. Beginwith the start of the procedure for "binary search for an error" by alias « g it b i s ect s tart " :


 
    $ gbss # git bisect start    

 

Note that the current, last in the branch, commit contains an error, alias « g it b i s ect b ad :


 
    $ gbsb # git bisect bad    

 

Now mark the commit, which guarantees the working state of the application « g it b i s ect g ood " :


 
    $ gbsg HEAD ~ 20 # git bisect good HEAD ~ 20    

 

And now it remains to continue to answer the questions of Geeth with phrases gbsb or gbsg , and after finding the culprit to drop the procedure:


 
    $ gbsr # git bisect reset    

 

And I do write these abbreviations when using this tool.


 
Search for a commit with error
 
 
    $ gbss # git bisect start
$ gbsb # git bisect bad
$ gbsg # git bisect good
$ gbsr # git bisect reset

 

 

We are looking for the instigator of lawlessness


 

Even with a high percentage of code coverage tests, no one is immune from the situation when the application falls and kindly points to a specific line with an error. Or, for example, in our case, we want to know who committed an error in the second line of the file a.md . To do this, run the command:


 
    $ gbl a.md -L 2 # git blame -b -w a.md -L 2    

 

You see, the counterparty Oh My Zsh did not just alias the command git blame , and added to it keys that simplify the search for the immediate instigator.


 

Bonus


 

View the list of commits


 

To view the list of commits, use the command git log with additional output formatting keys. Usually this command, along with the keys, is entered into the custom aliases of the Gita. We are lucky with you more, we already have a ready alias from the box: glog . And if you installed the utility tig on the advice of the beginning of the article, then you are the absolute champion.


 

Now, to learn the history of commits in the console in a very convenient form, you need to type the word git on the contrary:


 
    $ tig    

 

The utility also gives a couple of useful additions that are not in the Gita from the box.


 

First, the command to search the contents of the history:


 
    $ tig grep    

 

Secondly, a list of all sources, branches, tags, along with their history:


 
    $ tig refs    

 

Third, you can find something interesting for yourself:


 
    $ tig --help    

 

Accidentally made git reset --hard


 

You worked on the branch. elixir All day:


 
    $ glog
* 17cb385 (HEAD -> elixir) Refine Elixir article
* c14b4dc Add article about Elixir
* db84d54 (master) Initial commit

 

And at the end of the incident, everything was deleted:


 
    $ grhh HEAD ~ 2
HEAD is now at db84d54 Initial commit

 

No need to panic. The most important rule is to stop performing any commands in the Gita and exhale . All actions with a local repository are written to a special log - reflog . From it you can get the hash of the desired commit and restore it in the working tree.


 

Let's look at the reflog, but not in the usual way through git reflog , and more interesting with a detailed interpretation of the records:


 
    $ glg -g    

 

We find the hash of the desired commit 17cb385 and restore it:


 
    # Create a new branch with our commit and switch to it
$ gcb elixir-recover 17cb385
# Remove the old branch
$ gbd elixir
# Rename the restored branch back to
$ gb -m elixir

 

Randomly instead of creating a new commit made changes to the previous


 

Here again, the reflog comes to our aid. We find the hash of the original commit 17cb385 , if we cancel the commit immediately, instead of searching for a hash, we can use the quick link to it HEAD @ {1} . Next we do a soft reset, the index is not reset:


 
    # Soft reset on the original commit
$ grh --soft HEAD @ {1} # git reset -soft
# Commit to the right
$ gcmsg "Commit description"

 

The branch is too outdated


 

Sometimes you start working on features, but its release is postponed indefinitely. You make a commit and switch to other tasks. Together with the team you make a lot of changes to the wizard and after a while you come back to the branch with features. You try to make a rebase, but it offers to sort out the conflicts in a dozen commits. You can try to solve them all or make it easier.


 

Let's look at the example of a branch with features called elixir :


 
    # Switch to the master
$ gcm # git checkout master
# Create a new current branch for the original feature
$ gcb elixir-new # git checkout --branch elixir-new
# We transfer the only commit with features from the obsolete branch to the new
$ gcp elixir @ {0} # git cherry-pick elixir @ {0}

 

So, instead of attempting to update the branch, we take and without problems transfer one single commit.


 

Removing important data from the repository


 

To delete important data from the repository, I have saved the following snippet:


 
    $ git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch    '--prune-empty --tag-name-filter cat - -all && git push origin --force --all    

 

Running this command will break your stash . Before performing it, it is recommended that you get all the hidden changes. More about this reception by reference .


 

Referring to the previous branch


 

When executing some commands that expect the name of a branch to enter, we can pass the hyphen - as a reference to the branch with which we came. It is especially good to use this trick for the checkout:


 
    $ gco - # git checkout -
$ gm - # git merge -
$ grb - # git rebase -

 

Delete all files marked in .gitignore


 

Another common failure is too late to add to .gitignore some unwanted files or directories. In order to clean them from the repository ( and remove from the disk ), There are already ready keys for the command git clean :


 
    $ gclean -X # git clean -Xfd    

 

Be careful!


 

How correctly to perebdet read further.


 

Why do many teams need the key --dry-run ?


 

The key is --dry-run just need to be careful when removing and updating tasks. For example, the previous section describes how to delete everything that is specified in the file. .gitignore . It is better to show caution and use the key --dry-run , to view the list of all files to be deleted, and only then execute the command without --dry-run .


 

Conclusion


 

The article shows the point for optimizing the work activity of the programmer. Remember 10-20 mnemonic abbreviations are not difficult, forget the original team is almost impossible. The aliases are standardized, so that when the whole team changes to Zsh + Oh My Zsh , you can work with the same speed and comfort, even with pair programming.


 

Where to move next?


 

I suggest the following options:


 
  1.  
  2. Finally, sort it out, like Hit is arranged inside . It helps to understand what you are doing and why what you want to do does not work.  
  3. Do not be lazy once again to look at the documentation for the teams: git --help or ghh .
     
    See the full list of aliases by reference . Trying to remember them all is crazy, but using the list as a collection of a collection of interesting commands and keys to them is a good idea.
     
     
    Some aliases are made nontrivially, but are very useful in practice. Many of the presented aliases are not just shortenings, but small functions that further optimize the work. The use of the Geetha became more pleasant, the quality of the commits increased.
     
    I hope the material was useful, and you could learn something new for yourself. Or maybe they have already started actively implementing a new approach. Good luck!
+ 0 -

Add comment