{"id":484,"date":"2016-07-15T11:21:44","date_gmt":"2016-07-15T11:21:44","guid":{"rendered":"http:\/\/blog.nwareindia.com\/?p=484"},"modified":"2016-07-15T11:21:44","modified_gmt":"2016-07-15T11:21:44","slug":"git-best-practices","status":"publish","type":"post","link":"https:\/\/nishant.info\/index.php\/2016\/07\/15\/git-best-practices\/","title":{"rendered":"GIT Best Practices"},"content":{"rendered":"<div class=\"content_body has-bottom_margin\" data-view=\"content#body\">\n<p>This resource contains a collection of Git best practices and Git tips.<!--more--><\/p>\n<p>Git is not only a version control system, but also a collaboration and release management system. Using and understanding Git is an essential skill for any development team. At the same time, Git is comprehensive and complex; even simple tasks may need commands that can only be executed from the command line (terminal) without any GUI help.<\/p>\n<\/div>\n<h2>Why Is Git Stash Dangerous?<\/h2>\n<p>Have you ever stashed your changes on your current feature branch, switched to the main branch to make a hotfix, and then went back to the feature branch? If so, you might have been in danger of unintentionally leaking some of the new feature files into the main branch.<\/p>\n<p>Consider the following scenario: On your feature branch, you created a new file <code>new-cool-feature.js<\/code>. Suddenly, an urgent fix was requested, so you did <code>git stash<\/code>. You checked out the master branch, created a file <code>controller.js<\/code>, did <code>git add --all &amp;&amp; git commit -m \u2018Fix\u2019<\/code>, and pushed the branch. Unexpectedly, <code>new-cool-feature.js<\/code> would end up being pushed to your master branch. This is because <code>git stash<\/code> works just like <code>git commit -a<\/code>, meaning it ignores new files that are not yet tracked by Git.<\/p>\n<p>This has two advantages:<\/p>\n<ol>\n<li>No need to memorize additional stashing commands, like list all stashes, or stash untracked files. It is the usual Git commit routine with <code>git add<\/code>, <code>git commit<\/code>, and <code>git log<\/code>.<\/li>\n<li>In case you have WIP commits on several branches, there is no need to pick the needed one when you are back, as in the case of a stash. It is always the same <code>git reset HEAD^<\/code>.<\/li>\n<\/ol>\n<p>However, I\u2019d say there is one case when <code>git stash<\/code> is safe and convenient to use, which is when you want to see how your uncommitted code changes the behavior of the software. In this case, you can quickly do <code>git stash<\/code>, see how it worked before your new changes, and then <code>git stash pop<\/code> to go back. Not stashing some files accidentally, in this case, has virtually no consequences, as you will unstash on the same branch in a moment anyway. There is also no issue of picking the right stash from a list.<\/p>\n<p>&nbsp;<\/p>\n<h2>How to Create Very Short Shortcuts?<\/h2>\n<p>Adding aliases to <code>.gitconfig<\/code> has the advantage of retaining Git autocomplete, but it also has a disadvantage. These commands are still at least five characters long, like <code>git c<\/code>, and five characters is still too long for a command that you type dozens of times throughout your day. If you take an alternative path and create a bash alias like <code>gc<\/code>, you will lose autocomplete. Luckily, there is a way to make autocomplete work with Bash aliases. Bash uses a command <code>__git_complete<\/code> that you can use to register your aliases. Add the following to one of your RC scripts:<\/p>\n<pre><code>alias gc=\u2019git checkout\u2019\n. \/usr\/share\/bash-completion\/completions\/git\n__git_complete gc _git_checkout\n<\/code><\/pre>\n<p>The second line eagerly loads Git autocompletion functions into Bash, without it, they are loaded only after you try to autocomplete your first Git command. To see a list of Git commands that <code>__git_complete<\/code> accepts, type <code>_git_<\/code> and trigger autocompletion. This is confirmed to work with Git 2.7.4 and Bash 4.3.12.<\/p>\n<p>&nbsp;<\/p>\n<div class=\"content_body has-bottom_margin\" data-view=\"content#body\">\n<h2>How to Automatically Track Branch on First Push?<\/h2>\n<p>How often do you find yourself pushing a branch, and getting the following error message:<\/p>\n<pre><code class=\"language-bash hljs\"><span class=\"hljs-number\">2.3<\/span>.<span class=\"hljs-number\">0<\/span> <span class=\"hljs-keyword\">in<\/span> ~\/.dotfiles on test $ git push\nfatal: The current branch test has no upstream branch.\nTo push the current branch and <span class=\"hljs-keyword\">set<\/span> the remote as upstream, use\n\n    git push --set-upstream origin test\n<\/code><\/pre>\n<p>Oh, yes, I forgot to use the <code>--set-upstream<\/code> (or its shorter version, <code>-u<\/code>) flag. Again. This is so frustrating, can we somehow automate it? The fact is, in 90 percent of cases you want to push your current branch to origin with the same name. Fear no more, as we have a solution for that.<\/p>\n<p>Put this in your <code>.bashrc<\/code> (or <code>.zshrc<\/code> if you are a Zsh user):<\/p>\n<pre><code class=\"language-bash hljs\"><span class=\"hljs-function\"><span class=\"hljs-title\">git_branch<\/span><\/span>() {\n  git symbolic-ref --short HEAD <span class=\"hljs-number\">2<\/span>&gt;\/dev\/null\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-title\">has_tracking_branch<\/span><\/span>() {\n git rev-parse --abbrev-ref @{u} &gt; \/dev\/null <span class=\"hljs-number\">2<\/span>&gt;&amp;<span class=\"hljs-number\">1<\/span>\n}\n\nalias gp=<span class=\"hljs-string\">'git push $(has_tracking_branch || echo \"-u origin $(git_branch)\")'<\/span>\n<\/code><\/pre>\n<p>This code sets a handy <code>gp<\/code> alias that sets tracking the branch on first push and falls back to usual Git push on subsequent calls:<\/p>\n<pre><code class=\"language-bash hljs\"><span class=\"hljs-number\">2.3<\/span>.<span class=\"hljs-number\">0<\/span> <span class=\"hljs-keyword\">in<\/span> ~\/.dotfiles on test $ gp\nCounting objects: <span class=\"hljs-number\">3<\/span>, done.\nDelta compression using up to <span class=\"hljs-number\">8<\/span> threads.\nCompressing objects: <span class=\"hljs-number\">100<\/span>% (<span class=\"hljs-number\">3<\/span>\/<span class=\"hljs-number\">3<\/span>), done.\nWriting objects: <span class=\"hljs-number\">100<\/span>% (<span class=\"hljs-number\">3<\/span>\/<span class=\"hljs-number\">3<\/span>), <span class=\"hljs-number\">290<\/span> bytes | <span class=\"hljs-number\">0<\/span> bytes\/s, done.\nTotal <span class=\"hljs-number\">3<\/span> (delta <span class=\"hljs-number\">2<\/span>), reused <span class=\"hljs-number\">0<\/span> (delta <span class=\"hljs-number\">0<\/span>)\nTo git@github.com:conf\/dotfiles.git\n * [new branch]      test -&gt; test\nBranch test setup to track remote branch test from origin by rebasing.\n<\/code><\/pre>\n<p>Exactly what we needed.<\/p>\n<div class=\"content_body has-bottom_margin\" data-view=\"content#body\">\n<h2>When Is It 100 Percent Safe to Rebase?<\/h2>\n<p>The main goal of rebasing is to get rid of redundant merge commits and utilize the commit-less fast forward merges instead. Rebasing and fast-forward merges work together and are useful in case of a distributed version control system that Git is.<\/p>\n<p>Imagine a case where you did some work on your feature branch and tried to push it into a remote repository, but your push got rejected, because your colleague had just pushed some changes before you. If at this moment you do <code>git pull<\/code>, then under the hood Git will execute <code>git fetch &amp;&amp; git merge origin\/new-feature<\/code>. But instead of the usual fast forward merge that simply adds new commits to your branch, in this case, it will additionally create an actual merge commit since your local <code>new-feature<\/code> and remote <code>new-feature<\/code> branches have diverted.<\/p>\n<p>This redundant merge commit can be easily avoided by doing <code>git fetch<\/code> and <code>git rebase origin\/new-feature<\/code>. Rebase will rewrite the history of your local branch to make it look like you did all your commits later than your colleague.<\/p>\n<p>Rebasing an unmerged local branch <code>new-feature<\/code> using respective remote-tracking branch <code>origin\/new-feature<\/code> is always 100 percent safe, because you rewrite only the unpushed part of your local commit history. Nobody has seen your new commits, and you can do whatever you want with them. This is the beauty of the distributed version control system.<\/p>\n<p>The only inconvenience is that in the case of a rebasing conflict, Git flips the roles in conflict markers of local <code>new-feature<\/code> with remote-tracking <code>origin\/new-feature<\/code> and calls the remote HEAD, when in the case of a merge conflict it would call the local HEAD.<\/p>\n<\/div>\n<div class=\"tip_category_contributors\"><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This resource contains a collection of Git best practices and Git tips.<\/p>\n","protected":false},"author":1,"featured_media":1232,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false},"categories":[85],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/posts\/484"}],"collection":[{"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/comments?post=484"}],"version-history":[{"count":0,"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/posts\/484\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nishant.info\/index.php\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/media?parent=484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/categories?post=484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nishant.info\/index.php\/wp-json\/wp\/v2\/tags?post=484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}