Category: Random

Operation Protective Edge: The Case For Israel

Here are a few issues and clarifications regarding Israel’s military and political actions during operation Protective Edge, in the form of addressing the most common accusations against Israel.

Israel is Causing a Humanitarian Crisis!

1) Even under fire, Israel is still supplying humanitarian aid to citizens of Gaza. Fuel, food, medical supplies, as well as electricity and water. Gaza is running on Israeli fuel and electricity, even as they fire rockets on Israeli civilians.

ref:
http://www.israelnationalnews.com/News/News.aspx/182689#.U8JHOo2SyYk,
http://www.israelnationalnews.com/News/News.aspx/182742#.U8JGso2SyYk

2) Gaza has an open border with Egypt (its South border). Egypt does not supply Hamas with humanitarian aid, nor does it allow Palestinians to come into Egypt.

Israeli is Attacking Civilians!

Even the most cynic of Israel’s critics should be able to realize Israel has much to lose with each civilian life – even assuming a completely selfish perspective with no care for loss of civilian life, clearly Israel loses much political credit when causing civilian lives. Wouldn’t Israel do its best to avoid this?

Israel’s Attacks Have Too Many (Mistaken) Civilian Casualties!

1) Israel pre-announces when it’s going to attack a house. This is in order to allow any civilians to flee the area. Naturally, this also allows combatants to flee the area, which is a significant military setback, especially considering Hamas combatants are always among civilian population.

The announcement is via:

  1. Leaflets in Arabic dropped in the area.
  2. A telephone call to the house prior to the attack.
  3. A “roof knocking”, a tiny, non-explosive missile to hit the roof of the house to signify the “seriousness” – this house is about to be bombed, yo.

Only after all these is a target hit.

Example: http://www.youtube.com/watch?v=v4q-_rKLPU8

2) Israel only attacks confirmed terrorist centers. Hamas (by their own admission) target civilians all the time, as is clearly evident by indescriminate rocket strikes at civilian cities, kidnapping of civilian teens, and attempted terrorist infiltrations into civilian population centers. E.g., check out Wikipedia’s list of Palestinian suicide attacks. Remember this is the list of successful suicide attacks. For each such successful attempt, Israel’s security apparatus stops ten-fold failed attempts. Also take note of the list of civilian targets – bus stops, restaurants, markets, cafes, and so on.

3) Hamas uses human shields as a matter of routine, hiding arms and combatants amongst civilian houses, mosques, schools and hospitals, as well as encouraging civilians to rush to targets which are about to be bombed (as noted above) in an effort to either stave off the attack or “die as martyrs”.

Examples of Hamas spokespeople referring to these human shields:

Gazans tell how Hamas uses them as human shields:

4) Hamas routinely hides rockets in houses and schools. If civilians homes are used as military bases, any injuries incurred by these civilians is on the fault of whomever is storing the weapons there. Hamas even uses ambulances as part of the terror arsenal:

Civilian deaths in Gaza are the fault of Hamas. All casualties would cease immediately if Hamas stops its fire.

Israeli Response is Disproportionate!

1) Israel’s response is more moderate than, arguably, any other modern western country. How would the US react if thousands of rockets were being fired at NYC and DC? How would Russia react if missiles were being fired at Moscow? Israel has offered multiple times “quiet for quiet”, which has been rejected by Hamas.

Missiles have been fired at Israel from Gaza continuously ever since Israel withdrew (unilaterally) in 2005 from the Gaza strip. Hamas is now firing missiles How would your country react to a decade of being continuously bombed? How is Israel supposed to show restraint when Hamas is firing rockets at Israel, not even making any demands other than calling for the destruction of Israel?

2) Gazan death toll is higher (and any civilian death is a tragedy, to be sure) than Israels only for lack of Hamas ability. Hamas clearly state that were it up to them, they would kill any Jewish man, woman and child in Israel – it is not for lack of wanting that they (usually) fail to do so. Israelis run for shelter upon hearing sirens, rather than running for the roof to act as a human shield.

Israel also has far better defensive and offensive infrastructure because Israel uses its time and money building a country rather than perpetrating Jihad on its neighbors. Any country which wishes to have nonviolent peace with Israel can receive quiet from the Israeli side. Towards this end Israel has made peace with Jordan, peace with Egypt (including giving back the Sinai peninsula, which was 2/3 of Israel’s land at the time), and withdrew from the Gaza strip unilaterally.

  • Hamas charter excerpts: http://fas.org/irp/world/para/docs/880818a.htm, article 13: ‘[Peace] initiatives, and so-called peaceful solutions and international conferences are in contradiction to the principles of the Islamic Resistance Movement’

Israel has been under Islamic militant fire for 66 years, often close to the point of obliteration. This fire has ALWAYS included civilian targets, and – by open admission of parties such as Hamas, Syria and Hizballah – will not stop until the Jewish people are eradicated from Israel. Considering that despite all the above Israel still makes every effort to avoid civilian casualties, this is clearly not a disproportionate response.

It’s Israel fault, because…

…of the Blockade On Gaza! The point of the blockade is to prevent Hamas from building arms and rockets, which it will use to bomb Israeli civilian cities, as it indeed is doing. This conflict seems to prove the blockade is quite justified. Humanitarian supplies are being supplied to Gaza by Israel itself, and can be supplied via the Egyptian border as well (see above, but they’re not).

…Israel isn’t making peace with the PLO! When Israel withdrew in 2005 from Gaza, it withdrew unilaterally, freeing the Palestinian people to do whatever they wanted. What they did was to promptly elect Hamas and immediately begin firing on Israeli civilian settlements. It’s been a decade of that, now, no matter what happens in the Israeli leadership or policy. (As mentioned, armed resistance is the proclaimed slogan directive of Hamas – they will fight Israel until they banish all the Jews from Israel.)

Israel is understandably “reluctant” to allow a similar situation in the West Bank (which is much larger and even closer to Israeli main cities). More importantly, Hamas doesn’t care about any such peace agreement and explicity renounce any peace dealing with Israel. As their charter says explicitly, “There is no solution for the Palestinian problem except by Jihad”

…of the settlements! Well, there’s always something. Israel was under attack before any (post-1967) settlements existed – including terrorist attacks against civilian populations – and even before 1948. Even the worst critics of the settlements cannot justify attacking civilian population with rockets. Even Hamas themselves proudly proclaim that nothing bar a complete removal of all Jews from Israel will stop them.

Why doesn’t Israel trust the United Nations?

1) Historically, the United Nations has always acted to restrain Israel, while never acting to restrain anti-Israeli forces. This was observed in the wars of 1967 & 1973 (when Israel was on the verge of destruction) as well as the Lebanon wars of 1982 and 2006. In all the above cases the UN failed to prevent attacks against Israel, opting instead to leave the area when the conflict began.

2) UNRWA is the ONLY UN organization for refugee assistance that exists towards a SPECIFIC group of people. Its goal is not the expected assistance of Palestinians, but explicitly making them return to Israel. To repeat: these “refugees” have been in “refugee” status for 50 or 65 years (depending on who you ask), and are still living in refugee camps, instead of being resettled elsewhere. Despite the fact that Jewish refugees from Northern Africa, Middle Asia, and all of Europe fled at the same time – no UN agency has been formed to help the Jews, but one exists for the Palestinians. These Palestinians could have long been resettled if that was the objective, rather than an anti-Israeli objective.

UNRWA funds schools which brain-wash education of Gazan kids to hate Israel, and even have Hamas members on their payroll.

3) The United Nations “Human Rights Council” has a comical anti-Israel basis. Despite having countries such as Sudan, Syria and Iran in its body, its council has (per Wikipedia):

  • as of 2014, condemned Israel in 50 resolutions – more than the rest of the world combined
  • The council voted on 30 June 2006 to make a review of alleged human rights abuses by Israel a permanent feature of every council session
  • Their self-proclaimed mandate is to “investigate human rights violations by Israel only, not by Palestinians.”

Beyond critical, this bias seems simply ridiculous. Well at least this is admitted by the UN Secretary-General, Ban Ki-moon.

4) Iranian officials proudly support terrorism against Israeli civilians and development of nuclear weapons while they proclaim they will “destroy Israel”. The UN’s response has been meek.

The international community has never supported Israel, and it should be no surprise it does not support it now, despite valiant efforts to show restraint and address humanitarian concerns while its cities are (again/still) under fire.

But, but…

Hamas is the democratically-elected leadership of the Gaza strip. It is up to the Gazan people (and/or the international community) to restrain the unilateral attack on Israel and substitute it with a quiet that will be met by Israel, as always, with more quiet.

Israel does not want “to kill all the Arabs”; Hamas DOES want “to kill all the Jews”.

Israel observes human rights, Hamas does not (including the Red Cross Charter).

Israel is a western, modern country trying to allow its citizens a normal life while demonstrating remarkable military restraint in order to preserve human rights.

Israel sanctifies life, Hamas sanctifies death.

Israel is doing the best it can to keep on living while minimizing civilian casualties and observing human rights — the world should be supporting it, not bashing it. Despite being under rocket fire from Gaza, Israel is still the only entity in the world supplying humanitarian aid to Gaza, and Gaza — as we speak — is running on food, fuel, and water coming in from Israel.

The international media coverage of the current conflict is appalling. It forces Israel into a situation where they cannot trust anyone but themselves for defense or support. The hatred is disgusting, and the onus and blame of civilian deaths is on Hamas and on the international community for not reigning it in. Civilian deaths are terrible and they are the fault of Hamas.

If it were up to Israel, peace would be achieved immediately.

Advertisements

Ideas

Here’s a list of some web-app ideas I’ve been thinking about. 

1. Daat – Quality-controlled free-form Q&A site(s).

Quora has proved that a market exists for such a site, and has convinced its investors to the tune of a $1bn. They have not yet captured the whole market, though, and most notably they remain largely invisible and uninteresting to anyone whose first language is not English. 

2. NKH (No Kupat-Holim) – An online doctor’s examination 

Much medical interaction consists of formatted informational q&a / flow-charts which is the forte of online web applications. This has naturally led to people resorting to using the web to diagnose themselves, but no clear leader has emerged to replace the tier-0 functionality of forums and “googling your symptoms”. A dedicated website, allowing you to adequately identify specific symptoms as well as browse others’ anonymous diagnoses and/or a premium live response from paid doctors would be great. 

It’s one of those things that you just know are going to happen sometime – why sit in line to talk to someone about why your stomach hurts, when you can ask every doctor in the world? 

3. Micropayments Portal – an easy way to pay small amounts online. 

Most people won’t pay for stuff online because of a combination of:

  1. It’s a hassle. 
  2. You can usually get whatever you wanted for free instead of paying for it.

But it doesn’t have to be that way. If you could hassle-free pay very small amounts (say, less than 1$) people would be much more inclined to use such payments. These payments could be used anywhere – to read articles, donate money, in-(web)-app purchases…


If any of these interests you, drop me a line: sella.rafaeli@gmail.com. 

I believe that …

I believe that every time a developer implements infinite scrolling, a kitten orphanage catches fire, everyone dies, and the world becomes a worse place.

(src: http://blog.makandra.com/2011/11/i-hate-infinite-scrolling/)

Haha – well I actually think infinite scrolling is an amazing good (or should I say, basic) UX. But I enjoy generic bitching and the ‘every time X, something horrible’ meme. 

Side note – ‘infinite’ is one of the harder words to type. 

Git Sandbox (Book)

Welcome to Sella’s Git Sandbox (Book). Find me at sella.rafaeli@gmail.com.

We will cover the following topics:

  1. Command-Line Prompt
  2. Log
  3. Committing Changes
  4. Creating a new branch
  5. Comparing branches
  6. Finishing a Feature – Standard Flow
  7. Rebasing over Master
  8. Rebasing over Master – Going Deeper
  9. New Branch out of Existing Branch
  10. Rebase Interactive
  11. Rebase vs Merge: Why You shouldn’t Merge From Master
  12. Conflict Resolution
  13. Conflict Resolution in the Terminal (Advanced)
  14. Undoing an Uncommitted Change
  15. Undoing a Commit
  16. Cherry-Picking
  17. HEAD, Index, Working Directory
  18. Stash
  19. Default Text Editor
  20. Aliases
  21. SCM-Breeze
  22. GUIs
  23. Remotes: Introduction
  24. Remotes: Inspection
  25. Remotes: Tracking
  26. Remotes: Pulling
  27. Remotes: Ref-specs (advanced)
  28. Remotes: Pushing
  29. Remotes: Failed Pushes
  30. Remotes: Diffing
  31. Miscellaneous
  32. Epilogue

Introduction

We will learn some basic and advanced Git the slow and easy way using a renewable sandbox. You can make as many mistakes as you want and we’ll clean them up and restart. This tutorial assumes you’ve already got Git setup, possibly with your organization’s repository, and that you understand the basic concepts of version control.

The whole tutorial should take you about an hour or two, but you are encouraged to play around with the commands as much as you need to further your understanding.

Pre-Setup Tips for Unix nOobs

Some Unix-foo you should be familiar with before we start:

  1. When I (or anyone) write “$ blah”, they mean ‘put the command “bla” on your command line’. The $ is a standard notation for ‘your Unix command-line.’ “#”s in this context are comments.
  2. The command ‘echo “foo” >> bar_file’ appends the string ‘foo’ to the file bar, and is a quick shorthand way to edit files.

Setup

Run the following line in your terminal.

curl https://raw.githubusercontent.com/SellaRafaeli/bash/master/shell_scripts/git_sandbox >> ~/.sgsb1; source ~/.sgsb1; zz;

This sets up a git ‘sandbox’ with several branches with files and commits with which you can play.

Each branch has one or more files and commits (generally the files and commit messages will match the name of the branch). Assume your feature branch is ‘foo’ branch, and practice your standard (or exotic) git commands from it – diff from master, rebase over master, cherry-pick from branch bar, create a sub-branch, reset –soft and –hard, and so on.

When you want to start over, run ‘zz’ again in your terminal, and the sandbox will be reset to scratch. This means you should NOT be afraid, and indeed you should hammer git as hard as you can until you understand what’s going on.

The following lessons explain the important (and good) parts of Git. Before each lesson you should reset your sandbox to ‘zz’, and after each lesson you should make sure you understand how to execute the topic discussed.

Command-Line Prompt

Run:

$ zz #refresh sandbox

By looking at your command-line you should be able to see at least:

  1. which directory you’re in,
  2. which Git branch you are currently on (‘master’, by default),
  3. Your current Git commit status (do you have non-committed changes).

Make osure your branch reflects all these. #1 and #2 should be immediately evident, and try switching branches to to verify number #3, make a change in some file and make sure you see the change in the command line (one common standard to denote a ‘dirty’ file is a ‘*’ in the command-line.

Practice:

$ zz 
$ git checkout foo #switch to foo branch
$ echo "another line" >> foo_file #append another line to file named foo_file, make sure you see a 'dirty' state in the command line.

Links:

Git Log

As in every lesson, run ‘zz’ to start afresh.

Each ‘branch’ is a bunch of commits.

On master branch, run ‘git log’ and see our list of commits. You can see each commit has some metadata (unique hash as id, author, date, and commit message). Each commit reflects some changes made to the project.

On master branch, run ‘git log -p’. This shows you the verbose commit log – that is, the list of commits, and each commit’s details: what exactly has changed in that commit. Notably, each commit has a ‘hash’ which is a unique identifier; in essence, it is the commit’s ID. This ID is used whenever we want to perform an operation (including viewing) a specific commit.

The log is an incredibly important tool and you should make sure you feel comfortable with it. The are many ways to view the log. For example, try running:

git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

or

git log --pretty=format:'\''%C(red)%h%C(yellow)%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%cr)'\'''

Those are much nicer ways of viewing the commit log. To make sure you can invoke it easily, set it up as a global terminal alias, or as a git alias. One easy way of doing it is running the following:

git config --global alias.gl log --pretty=format:'\''%C(red)%h%C(yellow)%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%cr)'\'''

Now, whenever you run ‘gl’ (short for “git log”) it will display the nice pretty log. You should be doing this a lot as you apply commits, to understand what’s going on. Try to apply a couple commits and then reinspect the log and see that they’ve been added. Switch to another branch and reinspect the log, to see that on the other branch they are not present.

Practice:

$ zz #reset sandbox
$ gl #view master's log, notice commit messages regarding changes to master_file
$ git checkout foo
$ gl #view foo branch's log. Notice it only has part of master's commits, and then foo branch's commits.

Links:

Committing Changes

As in every lesson, run ‘zz’ to start afresh.

Using your text editor, open and change an existing file. Save it. You should see a ‘dirty’ state in the command line prompt. View ‘git status’ to see the changes Git has noticed, though they’re “not staged for commit”. Add the file to the ‘staging’ area using ‘git add #name_of_file’ (e.g., ‘git add master_file’). ‘git status’ again to see the change now ready to be committed. Now commit the changes using ‘git commit -m “some_message”‘, and view the log again to see your commit on top.

Practice:

$ zz #reset sandbox
$ # add a line to master_file
$ git status #see file is changed but not staged for commit
$ git add changed_file 
$ git status #see file is ready for commit
$ git commit -m "my staged & commited change" 
$ gl #see your commit added to log
$ git log -p #verbose log, see your change 

The ‘staging’ area is an intermediate step which you don’t have to use. It adds complexity which is usually not needed and I advise not using it at all until you feel more comfortable with Git. So, let’s repeat adding committing a change, this time without using the staging area. So, open your text editor and change a file. Back in terminal, ‘git status’ to see Git noticed the file you’ve changed, and now commit the file using ‘git commit -am “some_other_message”‘. The ‘-a’ flag makes Git skip the ‘staging’ area, and you should basically always use it until you know better. View ‘git log’ again to see your changes on top.

Practice:

$ zz #reset sandbox
$ # add a line to master_file
$ git status #see file is changed but not staged for commit
$ git commit -m "my direct commit" 
$ gl #see your commit added to log
$ git log -p #verbose log, see your change 

New Branch

As in every lesson, run ‘zz’ to start afresh.

Let’s create a new branch, add some commits, and inspect the log. $ git checkout master #make sure we start from master $ git checkout -b new_branch #notice we’ve switched to this branch $ gl #inspect log. Should be the same as before, since we’ve only created a new branch, have not added anything yet. $ git branch –list #see all existing branches. Notice ‘new_branch’ is there. $ git checkout new_branch #notice command-prompt should indicate you’re in your branch.

Using your favorite text editor, add the line “hamster whiskey” master_file and commit it. View the log to make sure your changes have applied.

$ git checkout new_branch
$ #change master_file
$ git commit -am "hamster whiskey" 
$ gl #notice the new commit

If you’ve configured your git log to do so, you should see an indicator of where each branch’s “HEAD” is. Our new branch should be one or more commits ahead of Master, for example. Make sure you see this in the log.

Now, let’s switch back to master (git checkout master) and inspect the log. It should be missing our branch’s new commits, since they exist only in the branch, and not in master (yet).

$ git checkout master
$ gl #no hamster whiskey

Comparing Branches

As in every lesson, run ‘zz’ to start afresh.

The development normal flow is making changes on some feature branch and then adding your changes to the ‘master’ branch. Create a new branch, commit some changes and view the log to make sure they’re there. Now, from the branch we’re on, you can compare with Master by running ‘git diff master’.

Practice:

$ zz #refresh sandbox
$ git checkout -b dog_branch
$ # add the line "dog_line" to master_file and save it
$ git commit -am "adding dog_line"
$ gl #see the "dog_line" commit
$ git diff master #notice the diff in dog_line

You will see a list of differences between your branch and master, per file. Each file changed will have red lines (what your changes have ‘removed’ from master) and green lines (what your changes have ‘added’). You should be familiar with each and every change you will be adding to the ‘master’ branch, so you will be doing this comparison a lot.

Finishing a feature – Standard Flow

After you’re done developing your feature, you will want to add your changes into ‘master’. The general flow should be something like this:

  1. Finish development of feature.
  2. Checkout master branch and update it from remote origin (in case others have updated it in the meantime).
  3. Now your master branch is updated. Go back to your feature branch and ‘rebase’ your feature branch over master, thus pulling master’s latest changes into your branch. (More on this later.)
  4. Now your master branch is updated, and your feature branch is based on the up-to-date master, and also has its own changes.
  5. Compare your updated branch to master using ‘git diff master’ from your branch. You should see only the changes you introduced.
  6. Look at your branch’s log (‘gl’). You should see your branch’s commits on top of master’s commits.
  7. Push your master branch.

In the next few lessons we will practice these steps.

Rebasing over Master

As in every lesson, run ‘zz’ to start afresh.

Suppose you’re done with your changes on branch ‘foo’ and you want to update your branch with latest changes to master. In our sandbox, ‘foo’ has some changes to master, but is missing changes done after it branched off (just like you might be in real life, as other developers have been adding to master).

$ git checkout foo 
$ gl #notice we have some commits done after branch off from master
$ git diff master #notice we are also missing some commits from master
$ git rebase master #git will grab master's new commits and reapply ours on top of them
$ gl #notice our commit log now has all the commits
$ git diff master #notice the only difference is now what we have that is not yet in master
$ git checkout master 
$ git merge foo #notice now master has all the changes done in foo as well

Rebasing over Master: Going Deeper

As in every lesson, run ‘zz’ to start afresh.

Rebase is the first ‘advanced’ topic, that might differ from many naive Git tutorials. We will not teach you the simplest way to get things done, but the best way. It won’t be hard. Keep swimming. Do it twice.

As you recall – suppose you’re on your feature branch and you’ve done making your changes. You are ready to add your changes to master branch. The correct flow is as follows:

  1. Checkout master and pull its changes from remote server, so you have the updated master.
  2. Checkout your branch, and rebase it over master. Solve conflicts if arise.
  3. Diff with master to make sure you approve all changes you’re about to add to master.
  4. Checkout master and merge in your branch.
  5. Push master to remote to share with everyone.

In this tutorial we do not have a remote server, but we have simulated that for you. Checkout ‘foo’ branch (git checkout foo) – assume on that branch you have added the ‘foo’ feature to the foo file. Diff with master — notice that there are parts that we (foo branch) have which master doesn’t have (displayed in +green), but there are parts which master has and we don’t have (displayed in -red). This is because master branch has commits that were done after we checked out foo branch.

In an organization, this is very standard; We checked out a branch and made some changes in our branch, but in the meantime other changes were added to master. So we have things master is missing, and master has things we are missing. We’ll ‘rebase’ our branch over master by adding master’s new commits to ours, by doing:

$ git checkout foo #if we're not already in foo branch
$ git rebase master 

‘git rebase master’ finds the point at which foo branched off of master, then applies all the commits done on master since, and then applies all of the current branch’s (foo’s) commits. The end result is that we have foo’s commits on top of all of master’s commits, which logically is exactly what we want – it’s as if we had branched off of the most recent master and then applied all of our commits.

Now our branch is updated with the most recent master, and we are satisfied with the diffs we want to add to master. So: ‘git checkout master’ followed by ‘git merge foo’.

This is a nuanced topic many (many!) Git users do not understand. I strongly recommend resetting the sandbox and performing the rebase again so you understand what’s happening.

$ zz #reset sandbox
$ gl #notice master's commits
$ git checkout foo
$ gl #notice foo's new commits, but missing some of master's commits
$ git diff master #notice we are missing some of master's changes
$ git rebase master
$ gl #notice foo's commits on top of ALL of master's commits
$ git diff master #notice diff now includes only foo's new changes

Many naive tutorials suggest doing ‘git merge master’ instead of ‘git rebase master’. Reset the sandbox and try it to see the difference – ‘git merge master’ will result in a git log containing a mixture of foo’s and master’s commits. The end result in the code will be the same, but inspecting the log will not show the correct chronological changes.

For further information on why you should rebase over master (rather than merge) when you’re done with your branch, see

New branch out of existing branch.

As in every lesson, run ‘zz’ to start afresh.

You can create branches out of any branch, not just out of ‘master’. Checkout an existing branch (git checkout foo) and view the diff with master. Now create a sub-branch out of that branch (git checkout -b sub_foo), make some commit. View the log, and check the diff with the father branch (git diff foo) and then check the diff with mater (git diff master). Notice the predictable differences – sub_foo already has foo’s commits, so they only show up when diff’ing with master (and do not show up when diff’ing sub_foo with foo).

Practice:

$ zz #refresh sandbox
$ git checkout foo
$ gl #notice we have foo's commits
$ git checkout -b sub_foo
$ # add the line "sub_foo" to foo file.
$ git diff foo #only 'sub_foo' line is different
$ git diff master #both sub_foo and foo lines are different

Why is this important? Suppose you are on branch ‘foo’ and want to rebase over master. Or revert, or reset — or any other git command, and you’re afraid you’re going to fuck things up. And indeed, you might, but you shouldn’t be afraid to experiment – it’s the only way you’re going to learn, after all.

So you before rebasing branch ‘foo’ over master, for example, you might prefer to create your own branch ‘sub_foo’ (out of ‘foo’, so they’re identical before you start rebasing). That way if things turn to shit, branch ‘foo’ is always there waiting for you. (There are also other ways of achieving the same ends such as pulling from remote, but we’ll discuss that elsewhere.)

This is a good point to mention that ‘master’ is just a regular branch, which by default is the first and by convention the ‘main’ branch.

Rebase Interactive

Either right before or right after rebasing over master, you might want to collapse many commits into one or into a few. This is important in order to have a clean, relevant commit log.

This great functionality is described in-depth here:

(You should also have a git editor you are comfortable with. See below for further details).

Practice by:

  • Performing a rebase-i on new branch ‘bob’ such that it only includes one single commit, then rebase the branch over master, then merge into master. Notice how master only has one single ‘bob’ commit added to it.

Practice:

$ zz # refresh sandbox    
$ git checkout -b bob_branch 
$ # create 4 commits, for example as follows:
$ echo "bob one" >> master_file;
$ git commit -am "bob first commit"
$ echo "bob two" >> master_file;
$ git commit -am "bob second commit"
$ echo "bob three" >> master_file;
$ git commit -am "bob third commit"
$ echo "bob four" >> master_file;
$ git commit -am "bob fourth commit"
$ gl #see your 4 commits
$ git rebase -i HEAD~4
$ # change your multiple commits into one commit using the instructions in the link
$ gl #see one commit for all of bob branch feature.
$ git checkout master
$ git merge bob_branch
$ gl #see how new log has only added one commit to it
  • Rebase an existing branch (foo) over master, then perform a rebase-i post the rebase, such that you remain with only one ‘foo’-related commit, then merge into master. Notice how master only has one single ‘foo’ commit added to it.

Practice:

$ zz #refresh sandbox
$ gl #notice master has 8 commits
$ git checkout foo 
$ gl #notice foo branch has 4 commits of its own over 4 commits in master
$ git rebase master
$ gl #notice rebased foo branch now has its 4 commits over all of master's 8 commits
$ git rebase -i HEAD~4
$ # change your multiple commits into one commit using the instructions in the link
$ gl #see one commit for all of bob branch feature.
$ git checkout master
$ git merge foo
$ gl #see how new log has only added one commit to it

A clean commit log is easier to read, revert (if necessary), and cherry-pick into other branches (if necessary). For more on these, see below.

Rebase vs Merge: Why You shouldn’t merge

What many naive Git tutorials suggest is ‘merging’ instead of ‘rebasing’. We will explain the difference in a nutshell, and then you will be able to see it yourself in the sandbox.

Suppose you are on branch ‘foo’ and you want to add all of master’s commits to your branch (which you should do before adding your branch back to master, see “Finishing a Feature”, above). If you merge/rebase, Git finds the point where you ‘branched off’, and then applies all the commits since that point – from both the source branch (the one you are merging/rebasing) and the new branch.

So, if we are in ‘foo’ and hit ‘git merge/rebase master’, Git finds where ‘foo’ branched off of ‘master’ and then reapplies all the commits from ‘master’ and from ‘foo’. The difference is the order in which it will reapply them.

If you ‘rebase’, the order will be first all the commits from master, then the commits from ‘foo’ (which is what you want — your commits “on top” of everything else). If you merge, the order will be interspersed (mixed-up) — it might be master-foo-master-foo. This is bad, because the resultant commit log will be a mix of master’s and foo’s, instead of foo-on-top-of-master, which, again, is what you logically want: your commits on top of master’s.

You can see this for yourself in the sandbox.

Practice Merging from Master (bad):

$ zz #restart sandbox
$ gl #notice master has 8 commits
$ git checkout foo 
$ gl #notice we have 4 of foo's commits, and 4 of master's commits
$ git merge master
$ gl #notice the commits are mixed-up: master's and foo's, interchangably. By just looking at the log, it is very hard to tell that we have just added 'foo' to 'master'.

Practice Rebasing over Master (good):

$ zz #restart sandbox
$ gl #notice master has 8 commits
$ git checkout foo 
$ gl #notice we have 4 of foo's commits, and 4 of master's commits
$ git rebase master
$ gl #notice the commits are in a good order: all of master's 8 commits, and above them we have foo's commits. Just by looking at the log, it is very easy to tell that we have just added 'foo' to 'master'. We can also rebase -i now (see above), further making our log cleaner and more agile. 

Conflict resolution

This lesson is lengthy, but not difficult.

When you ‘rebase’ or ‘merge’ you are applying commits from separate branches one on top of the other. Usually Git is smart enough to know how to deal with these, but occasionally you get a conflict – for example, if both branches edited the same line in the same file, Git won’t know what to do.

Let’s practice by creating our own conflict. We will create a branch and set line number 9 to “Red”, then set the same line in master to “Yellow”, and then try to rebase.

$ zz #reset sandbox
$ git checkout -b conf_branch
$ echo "Red Red Red" >> master_file 
$ git commit -am "adding branch-is-red";
$ git checkout master 
$ echo "Yellow Yellow Yellow" >> master_file 
$ git commit -am "adding master-is-yellow"

At this point you can inspect the master_file on both the conf_branch and on master_branch. Notice the difference where branch has ‘Red’ and master has ‘yellow’. This simulates us finishing up the feature and adding ‘red’, while in the meantime someone has changed master_file and has added ‘yellow’. Now let’s rebase.

$ git checkout conf_branch
$ git rebase master

Oh no! Git has hit an issue while rebasing, since it does not know which line to use – Red or Yellow? We can see Git declare the issue:

CONFLICT (content): Merge conflict in master_file
Failed to merge in the changes.

Git also tells us what to do:

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

First (actually, last), we see that we can run ‘git rebase –abort’. If this conflict scares you, run that — it will abort the rebase, going back to the previous stage.

Let’s rebase again, and this time we’ll solve the conflict.

gco -b conf; echo “Red” >> master_file; gcam “red”; gco master; echo “yellow” >> master_file; gcam “yellow”; gco conf; git rebase master; $ git rebase master #prepare to beat the conflict

Observe the error message – specifically the line “Patch failed at”: Git is telling you which commit it tried to apply which triggered the conflict. In our case it would be the commit adding “Red”. So Git is in the middle of a commit applying “Red” which it is stuck. What status are we in, then, exactly?

$ git status

We see the ‘master_file’ is under a status of ‘both modified’: both the branch and the source over which we are rebasing have modified it. Use ‘git diff’ to see the exact situation:

$ git diff master_file

We will see something like:

++<<<<<<< HEAD
 +yellow
++=======
+ Red
++>>>>>>> red

This is Git’s notation for conflicts:

  • The <<<< signifies the start of the conflicting area.
  • The HEAD is the “previous commit” (in our case, master’s top commit, since we’re rebasing over it)
  • Everything above the ==== is the version in the “previous commit” — as in, everything that was added to the file by the commit currently being applied.
  • Everything below the ==== is the version in our commit — as in, what was added to the file by someone else (the branch we are rebasing over).

To resolve the conflict, we have three options: take ‘their’ version (ignore this commit), take our version (ignore ‘theirs’), or merge them together manually.

Practice:

$ zz #refresh the sandbox
$ git checkout confl #a pre-made branch ready to be rebased with a conflict
$ git rebase master 
$ #solve the conflicts using master's texts, or your text, or both.
$ git add master_file
$ git rebase --continue

The manual way to resolve a conflict is to open the conflicting files in your text editor, go to the conflicting areas, and edit the text to whatever you want it to look like now. (Remember to remove the “<<“s, and eventually leave the file the way you want it). Now go back to the terminal, ‘git add’ the files you have edited, and commit them — just like any other commit. Then tell Git to proceed with ‘git rebase –continue’.

An alternative way of resolving conflicts, instead of using your text editor, is to use a “mergetool” – one of many lightweight GUIs to assist you in resolving the conflict. When you hit the conflits, run ‘git mergetool’, which will (after a prompt) launch a GUI tool to assist you in solving the conflict. When you’re done, save and close the mergetool.

Conflict Resolution in the Terminal

Practice:

$ zz #refresh sandbox
$ git checkout confl #pre-made branch ready to be rebased with conflict
$ git rebase master #hit error
$ git status #see which file has the conflict: master_file
$ git diff master_file #view the conflict and both versions
$ git checkout --theirs master_file #take 'theirs'

or $ git checkout –ours master_file #take ‘ours’

At this point you can inspect the file and see that indeed you have taken the correct version.

$ git diff master_file #either no change (ours) or some change (theirs)
$ git add master_file
$ git rebase --continue

When git-rebasing, ‘our’ version (yellow) is the one in the branch we are rebasing over (usually ‘master’), and ‘theirs’ is the version from the feature_branch. So if we are in ‘conf’ branch and doing a git rebase master, ‘ours’ is the master version and ‘theirs’ is the branch version. (If this seems backwards, imagine it is because the first thing rebase does is checkout the rebased version, and then reapply the branch commits on top of it.)

When merging, it is the opposite: ‘our’ version is the branch we are on, and ‘theirs’ is the branch we are merging in.

one from master, when rebasing over master) and ‘theirs’ is the one we are re-applying (red).

Links:

Undoing a Non-committed Change: Git Checkout

If you’ve made uncommited changes in your working directory, you can undo them by running “git checkout”, either on a single file or a directory.

Practice:

$ zz #reset sandbox
$ echo "another line" >> master_file 
$ git status #file has changed
$ git checkout master_file
$ git status #file is back to previous 

Behind the scenes: To understand why this works, in brief, Git keeps track of three things: the ‘last commit’ (referred to as HEAD), the ‘next commit’ (referred to as the Index or the Staging area, and I recommend not using it), and the working directory (your filesystem). Basically, ‘git checkout’ takes the HEAD of a file (or files) or a branch and sets it into your working directory. (And yes, this is also what ‘git checkout some_branch’ works).

Undoing a Committed change: Git Reset

If you’ve made changes and committed them, you can still undo them, as long as you haven’t pushed. (If you’ve pushed them to a remote you can still undo them, but other people might have already pulled those changes, which will cause much confusion, so don’t).

The way to undo commits is with “git reset”, by resetting to the last good commit you had. View the log, then ‘reset’ back to the last good commit’s hash. After resetting, the “removed” commits

Practice:

$ zz #reset sandbox    
# add 4 commits to master_file: 
# add "venus_1" to master_file and commit it under the message "venus_1"
# add "venus_2" to master_file and commit it under the message "venus_2"
# add "venus_3" to master_file and commit it under the message "venus_3"
# add "venus_4" to master_file and commit it under the message "venus_4"
# as a short-hand for the above, run the following line:
$ for var in {1..4}; do echo "venus_#$var" >> master_file; git commit -am "venus_$var"; done;
$ gl #see the log contains 4 'venus' commits
# copy the commit hash of the first venus commit (in my case, it's c9b6641)
$ git reset c9b6641
# now the commits of venus_1, venus_2, and venus_3 have been removed from the commit log. 
# The changes that were in those commits appear as uncommited changes in the working dir.
$ git status #see master_file now has uncommited changes
$ git diff master_file #see the reset changes appear as uncommited changes.
# you can now edit the reset changes and recommit them, or cancel them by running 'git checkout master_file' (see above).

When running ‘git reset [commit-hash]’, all commits above that hash are removed, and the changes they included appear as uncommited changes in your working directory.

If you add the flag ‘–hard’ (git reset –hard [commit-hash]) then the changes will be forcefully removed (will not appear in your working directory). If instead you add the flag –soft (git reset –soft [commit-hash]), then the changes will appear in your working directory, and will have already been added to your staging area.

I recommend not using the soft/hard flags as they are confusing/dangerous. Do a simple ‘git reset’ and then deal with the reset changes in your working directory as you wish.

Links:

Cherry-Picking:

Sometimes you don’t want to rebase/merge in another whole branch, but you just want to grab a single commit from that branch. You can do that by ‘cherry-picking’ that commit hash into wherever you want to apply it, so that you can apply a single commit from branch ‘bar’ to branch ‘foo’.

Practice:

$ zz #reset sandbox
$ git checkout bar 
$ gl #copy the first 'bar' commit hash. In my case it is a82d14d, and it is the commit adding the file 'bar'.
$ git checkout foo 
$ git cherry-pick a82d14d
$ ls #see we have added the file 'bar'
$ gl #notice we have a new commit (latest) adding the file bar.

As a side note, in some cases (such as if you take a commit changing to a file you do not yet have) you will run into a cherry-picking conflict, which should be resolved just like any other conflict. In the case of a missing file, make sure to ‘add’ it to resolve the conflict.

HEAD, Index, Working Directory

As you learn more and more about Git, you learn the terminology as well. Here are some approximations to help you understand Git literature and workings:

  • HEAD is your last commit. Each branch has is a list of commits, and the last commit of the current working branch is called HEAD. Naturally this means HEAD changes whenever you change branchs.
  • Index is your “next” commit, also called the ‘staging area’. You can ‘stage’ changes, bringing them into the Index/Staging area, thus creating a list of changes that will be commited once you run ‘git commit’. If you add the -a flag to committing (‘git commit -a’) then all changes (in tracked files) will be committed, not only the ones in staging. For simplicity, I recommend NOT using the staging area or Index at all until you are experienced with Git, and to always commit all changes.
  • Working Directory is the files on your disk. These files exist outside of Git as well, and you can access them in any way you please, from any editor or terminal. Any time you switch branches, Git modifies your working directory to reflect the contents of that branch.

Practice:

$ zz #refresh sandbox
$ gl #view log. Notice HEAD is the last commit on master.
$ ls #note no file called 'maz_file' exists in directory.
$ git checkout maz #switch to maz branch, which is 'ahead' of master.
$ gl #notice HEAD is the now the last commit on 'maz' branch. Note your log should also show you which commit 'master' branch is on. 
$ ls #note Git has updated working directory to include 'maz' file. 

Git Stash

Git won’t let you swap between branches when you have uncommitted code. It encourages you to either commit your code or ‘stash it’ into a stack of changes Git manages. You can read more about git stash online, but the simplest use case is temporarily ‘stashing’ your changes, switching branches, then ‘popping’ (re-applying) the changes the other branch (if so desired).

Practice:

$ zz #refresh sandbox
$ echo "test" >> master_file #add line to master file. Notice Git shows 'dirty' state.
$ git checkout maz #Git won't allow, tells us to commit or stash changes.
$ git stash #Note uncommited changes have been undone
$ git stash show #see the changes waiting for you in the stash
$ git checkout maz #now Git will allow you to switch 
$ git stash show #see the same changes -- stash is global, not under a specific branch.
$ git stash apply #reapply the changes, if you want to. 

Default Text Editor

Occasionally Git opens up text editors for you – to edit commit messages, rebase -i handling, and so on. The default text editor differs; often it is Vim or some other basic text editor. If you feel uncomfortable with Git’s default text editor, you can tell it to use a different one. This is set in Git’s config file, which by default resides at ~/.gitconfig. Open up that file with your favorite text editor, and add/modify the [core] section to include an ‘editor’ as such:

editor = subl -n -w

In this case we have used SublimeText, but you can use whatever application you want — just make sure the line defined by ‘editor = ‘ runs that text editor when you run it in your terminal. (You may have to preconfigure aliases or system path.)

Now, whenever Git needs to open a text editor, you will get you comfrotable text editor rather than Git’s default one.

Practice:

$ zz #refresh the sandbox
$ echo "read me in default text editor!" >> master_file
$ git commit -a #note no "-m", so Git will default text editor for the commit message.
# setup your text editor in Git config file.
$ zz #refresh the sandbox
$ echo "read me in your favorite text editor!" >> master_file
$ git commit -a #note no "-m", so Git will open your configured text editor for the commit message.
                #write commit message in your favorite text editor. 

Note, the Git config file has many options and goodies you can preconfigure to enhance your use.

Links:

Aliases

Unix systems terminals allow you to create aliases for common operations. Instead of writing ‘git checkout’ a million times, we will create an alias for that: ‘gco’. Aliases can be defined in various places; the default place is your ‘bash_profile’, which is loaded every time you open a new terminal.

Practice:

$ #open ~/.bash_profile in your text editor
$  #add the following as the first line of the file: alias gco='git checkout'
$  #save the file and open a new terminal
$ zz #reset the sandbox
$ gco foo #alias for git checkout foo
$ #notice switch to branch foo

You can thus speed up your Git experience by creating aliases for your common operations. My favorites are:

  • ‘gco’ for ‘git checkout’
  • ‘gs’ for ‘git status’
  • ‘gd’ for ‘git diff’
  • ‘gcam’ for ‘git commit -am’

SCM-Breeze

Now that you know about aliases, you can reasonably assume that others have already done it before you. You can use their packages for robust functionality. One such recommended package is SCM-Breeze. Check it out in the link below — it will supply you with many useful aliases, as well as a shorthand method of referencing files displayed in the ‘git status’. I heavily recommend using this (or other) such packages.

Practice:

1. Install SCM-Breeze
2. run 'zz' to refresh sandbox
3. Use the above shortcuts 

Practice:

$ #install scm-breeze
$ zz #refresh sandbox
$ echo "change" >> master_file
$ gs #see [1] master_file
$ gd 1 #shorthand for 'git diff [file 1]'

Links:

A word about GUIs

While we have been focusing on Git terminal usage, Git also has many, many GUIs. Many IDEs include their own flavor of a Git GUI. While this is a classic software “Holy War” (command-line vs GUI), I would recommend trying out both: GUIs often offer functionality which is difficult to replicate in command-line (“History of Selection” comes to mind), but my experience is that you only really understand what the hell you’re doing if and only if you are doing it in the command line.

As a footnote, Git often comes bundled with various GUI utils such as “gitk” or “git instaweb –httpd webrick” which give you various GUI abilities. Figure out what’s best for you.

Remotes: Introduction

The rest of this document will deal with ‘remotes’. This document does not currently include a tutorial to work with remotes, but you can set up a repository under your own user in github.com and practice with it. The following will simply be a list of issues you should be familiar with.

Assuming your repository has a remote configured, you can view the remote by running:

$ git remote -v

This will display the repository with which you are working. You should see two options: one for pulling (actually ‘fetching’, which is almost the same, as we’ll discuss later) and one for pushing. Presumably they would be the same one.

Working with remotes is important. Most commonly your ‘remote’ will be github.com or some other similar site (in this document, we will assume it is github). Your remote will also hold copies of many branches, and in general each local branch will have its counterpart in the remote.

So, your local branch may exist only locally, as is covered above. If you want to share your branch with others, you will probably want to put it on the ‘remote’ Git server.

Remotes: inspecting

You can go into github.com and view all the branches in your repository. (If your company has more than one codebase, your will have more than one repository, and you can browse each one separately.)

In each branch, you can see each file. You can inspect the contents of each file in each branch (in fact, you can even edit directly in github.com).

In each branch, You can see the list of commits in the project — this is the same commit log on your computer. If all participants keep the commit log clean – use ‘rebase’ & rebase -i’ to ensure they only add minimal, clensed commits – you can easily track the list of features and changes made to the codebase.

Practice:

1. Open your main repository in github.com on 'master' branch
2. View the commit log. 
3. Compare it to your local commit log on same branch ($ gl)

You can also browse individual files and their history.

Practice:

1. Open your main repository in github.com on 'master' branch
2. Open a specific file you are familiar with
3. View its commit log 

Remotes: tracking

Each local branch can ‘track’ one remote branch.

$ git branch -vv #shows you which local branch tracks which remote branch. 

However, do not naively assume that ‘git push’ and ‘git pull’ will push or pull from the branch you are tracking. It’s a bit more complicated than that — but we will try to implement a simple workflow, so you don’t have to remember all these.

$ git remote show origin #shows you all local and remote branches as well as tracking info, and which branch pulls from/pushes to which remote branch. 

There are many options to use this, but you should keep things simple: each local branch should either track no remote branch or track the remote branch with the same name. You can tell a local branch ‘foo’ to track a remote branch by name of ‘foo’ by running:

$ git checkout foo #enter 'foo' branch'
$ git branch --set-upstream-to foo #might show a warning if this is already the case. Now 'foo' tracks 'foo'.

You can use the above to understand how to make one branch track another with a different name, but I advise against it until you feel very comfortable with Git remotes.

You can also set the ‘upstream’ branch when pushing, by running:

$ git checkout foo #enter foo branch
$ #make some changes..
$ git push -u origin foo #push to foo, and set upstream tracked branch to foo.

Remotes: pulling

Running ‘git pull’ will pull the changes from the server into your branch. The basic flow you would have for updating a branch would be:

$ git checkout my_branch
$ git pull #or git pull origin my_branch. This branch now has merged the changes on the remote.

Some things you should know:

1. git pull == fetch + merge

By default, when you ‘git pull’ into a branch, you are merging the pulled new commits into your local branch. In some cases (like if you are committing directly to master), this is less than ideal, since when you push you will want your commits to be on top. In those cases run ‘git pull –rebase’ to do a fetch+rebase. You can also set pull to rebase by default; see links below.

2. git pull origin some_branch 

By default if you run ‘git pull’ it will pull the upstream branch (which should be the branch of the same name). You can explicitly pull any remote branch into your local branch:

$ git checkout foo
$ git pull origin bar

I would advise against doing this. You should use either the simple ‘git pull’ or ‘git pull origin foo’ when in branch foo. If you need to integrate changes from one branch into another, pull them both separately and do all the merging locally.

Links:

Remotes: ref-specs (Advanced)

Actually, when you ‘git pull’ git updates information about all of the remote branches — but it only performs the merge on the branch you are currently in. Thus, other branches are not updated, but information about them in the remote is updated.

You can see this in Git’s output after running ‘git pull’ (it shows you the list of branches for which it has updated the information).

Git stores the ‘remote’ version of each branch in a separate location, denoted by ‘origin/’. As in, you can compare your local branch ‘bar’ with remote ‘bar’ by running:

$ git checkout master 
$ git pull #local master is merged with remote master, other branches are not merged but our local git now has information about the remote branches
$ git checkout bar #bar has not been merged with its remote
$ git diff origin/bar # diff with remote bar
$ git diff origin/foo # diff with remote foo

Remember, git diff with origin/ won’t always be the diff with the ‘remote’: it is only the diff with the local data about the remote, which is obtained when running ‘git pull’.

Remotes: pushing

Running ‘git push’ will push your branch into the server. The basic flow you would have for updating a remote branch would be:

$ git checkout foo
$ git push #or git push origin foo. Remote branch foo will now have your code. 

Some things you should know:

1. 'git push origin foo' pushes your local branch foo to remote branch foo. 

2. You can use the shorthand 'git push' instead. When you do not name a branch, git's "default" push behavior is defined in gitconfig. 

In short, you should use 'current' ($ git config --global push.default current). 'Upstream', 'tracking' (deprecated) and 'simple' will also do. 

3. Remember 'git push' replaces the *entire* remote branch with your local branch - you are effectively replacing everything that is there. 

*. Advanced: 'git push origin foo' is shorthand git push origin foo:foo, which means pushing your local branch foo to remote branch foo. If you want to push local branch foo to remote branch bar, run git push origin foo:bar. 

Links:

Remotes: failing pushes

Sometimes when you try to push Git refuses to accept the push. This can be because Git does not know what the upstream branch is (or perhaps it does not exist yet in the remote) – in this case you can push with setting upstream by running:

$ git push --set-upstream origin foo 

or

$ git push -u origin foo

Both of which set the upstream to foo and then push to foo.

Other times, Git may refuse to allow you to push, because the remote has changes you do not have (yet). This may happen when collaborating on a branch with someone, and Git is protecting you – it is saying “do not push yet, things have changed”.

In such a case, you can update your local branch with the remote (git pull), resolve any conflicts, and then push.

An alternative is to push with –force ($ git push –force), which predictably forces your push despite Git’s warnings. This destroys anything in the server that you did not have, since you are replaced the remote contents with your own. If you are working on a solitary branch this is fine (since you would be replacing your own code with your own code); if working on a shared branch this means you might be demolishing some else’s code, so be wary.

Remotes: diffing

After running ‘git pull’, Git stores a local version of the contents of each remote branch. You can diff your local branches vs these branches as follows:

$ git checkout foo 
$ git pull #Git now knows what all remote branches look like. In addition, it merges local foo with remote foo.
$ git diff origin/foo #Will be empty, since we just merged foo with its remote.
$ git diff origin/master #Will show diff with remote master. 

Miscellaneous

$ git --version #self-explanatory
$ git config --list #see all config values, both set in your .gitconfig file and inherited

Epilogue

I had a really hard time learning Git. Sometime the best (or only) way to learn something is to explain to someone else – so, I hope reading this book has been at least as helpful for you as writing it has been for me.

For any issue please contact me: sella.rafaeli@gmail.com.

On the Perils of Failing Silently

Last week we discovered a bug in production where a certain user flow would crash. Naturally, since this was a high-profile flow, the bug was discovered on Thursday evening (the end of the work week in Israel). And naturally, we could quickly reproduce the error in our live site, but it would not reproduce in any non-production environment. Par for the course.

Diving into the issue, we saw that under this set of circumstances, the client was receiving a(n inappropriate) 403, with no further information. Since the flow did not require authentication, this was particularly suspect. We started iterating through the various usual suspects – could our nginx be at fault? Is our load-balancer denying this particular flow? A broken SSL certificate perhaps? Or was something in the code broken, or just deep-six’ing the request with no further info?

Our usual log systems did not show any errors, and upon further inspection we realized that the breaking flow did not result in any applicative logging at all, which was especially odd since we make heavy use of logs and error-log anything that breaks. The lack of applicative logs along with the silent 403 led to the expected back-and-forth between the application code developers and the dev-ops infra people, where each side assumed it’s the other’s fault. Hours spent, dollars lost.

Eventually we traced it down to a particular legacy before_filter (we ride on Rails) which was affected by recent site configuration changes. This before_filter denied the request, but did so extremely silently:

render :nothing => true, :status => 403 and return

Once found, we could quickly verify this was indeed the issue and fix the before_filter to match the configuration changes, making everything go back to normal. However, it had taken us precious time to debug this error – hours with the flow broken, affecting users.

This could have been solved much, much quicker if the before_filter would not be so silent. The act of denial could be appropriately logged, but that’s not so straightforward – we wouldn’t want to log it as an error (since a truthful denial/403 is not an error), and any non-error logging would not be immediately obvious (what we would be looking for, anyway?).

A good way to solve this would be to simply return a non-empty error message to the client. Say:

render :text => "Action denied, Sorry-O.", :status => 403 and return

With a non-empty error message as above, a simple grep would quickly locate the root problem, enabling near-immmediate response.

$ grep "Action denied, Sorry-O." -ir .

Don’t give out compromising information, but *say something*, so your error is identifiable. Rendering ‘nothing’ is the equivalent of saying “Why? Because Fuck You, that’s why.”

Moral of the story: Never fail silently. Just like kids are taught: if you see something wrong, SAY SOMETHING.

Git for Smart Noobs

One of the problems with technical topics is that the oftentimes experts have a very hard time explaining the complicated details to others with less of an expertise. The explanations, aiming for exactness and truthfulness, go over the student’s head and are lost.

In my personal (slow, arduous) journey to learn the basics of OS code development and Git, whenever I manage to reach a more-than-basic understanding of a more-than-basic topic I try to write a post to explain that topic. This (hopefully) results in:

  1. Others (other noobs) benefitting from a down-to-earth explanation in terms they can understand, and
  2. My better understanding of the topic, for the best way to understand something is to explain it.

I’ve been writing using ‘Medium’, a new blogging software, which is aesthetically very pretty and does a good job at it’s main claimed purpose, “getting out of the way” and allowing you to spill your ideas easily.

So far I’ve written on how to use git rebase and git reset. Check it out.

Vim Basics: .vimrc, Ruby Coloring and Syntax

I only use Vim when I have to. But sometimes, you have to – as in when working on a remote server. You might as well know what the hell is going on. So get comfortable with it. Here’s how to at least enable some sanity in your vim view.

1. Go to your root dir. Create/find a “.vimrc” file. (The ‘rc’ stands for ‘Run Commands‘, by the way) Just like bashrc, this file will run every time you run vim, so you can put some setup instructions here.

2. Go to (or create) ~/.vim/syntax. This folder holds the various syntax-highlighting rules files.

3. Execute wget https://raw.github.com/vim-ruby/vim-ruby/master/syntax/ruby.vim, for a file with Ruby syntax rules (Google around if you need a different language).

4. Back to ~/.vimrc, add the following:

:colorscheme delek
:syntax on
:set nu

The first command sets a nifty colorscheme, the second one turns on the syntax highlighting for ruby files, and the third one turns on line numbers.

5. Now vim your favorite ruby files, like a boss.