Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Flight rules for Git – What to do when things go wrong (github.com/k88hudson)
96 points by inertialforce on July 29, 2014 | hide | past | favorite | 29 comments


I was a little disappointed to not see anything I don't use regularly. Some explanation of reflog might be helpful, in addition to a bit of detail on git internals that explains why things in Git are never really deleted until you run `git gc`. For instance, just yesterday I realized that a branch I had deleted erroneously (bad branch name) contained a few days of work. I looked in git reflog to find the SHA for the last time I checked it out, checked out that SHA, then made a new branch. No work lost. If I didn't know that, I'd be out a few days of effort.


> things in Git are never really deleted until you run `git gc`.

wording there is a bit dangerous, see this snippet from `man git-gc`:

    Some git commands run git gc --auto after performing operations that could create many loose objects.
It doesn't say what those commands are. I've always found what I'm looking for in the reflog, so either I've been lucky or this cautionary note in the man page is conservative.


`git gc` will not remove objects mentioned in the reflog. The reflog entry for a commit that is not referenced from any refs (e.g., because you deleted the branch it was on) will last for `gc.reflogExpireUnreachable` time units. By default this is 30 days.

After that, then the object is subject to pruning by `git gc`, and may go immediately, or up to 14 days later, depending on the packing. That 14-day grace period is there for objects that never got referenced in the first place (so a tree that you are building to make a commit, for example, would not go away before you run `git commit`).


git-gc defaults to preserving any objects less than 14 days old. This is configurable.


Great suggestions, thanks :)


No warning on rebasing or amending pushed changes make this pretty unhelpful.

Edit: Hang on it's worse then that, it just says 'always force push your changes' - wonderful, you might drop commits that were previously on the branch head that someone else has pushed. Hooray.


Yea, I read the force push and was a little shocked. Admittedly, having local and remote branches that have diverged has ended up being one of the biggest problems for me using Git. I was force pushing to my remotes to sync everything up until I read up on this and realised that this screws things up if anyone else has checked out your remote. So little puzzled that they recommend this. I also haven't found out what the modus operandus is to get everything to sync up easily. Anyone know if a workflow to deal with local/remote divergence is documented somewhere?


I'm not sure you need a "workflow". In the case of a complex divergence on branch "foo" my procedure would be:

0. Be on local branch "foo". If you've just tried to pull and got conflicts, abort the merge. (Note that for this to work reliably, you should never pull without first committing or stashing your changes):

    git merge --abort
1. Create a new branch "m":

    git checkout -b m
2. Merge origin into m, in several pieces if necessary:

    git merge origin/foo
    git merge [hash of some intermediate commit on origin/foo]
3. Once you're happy with all this, switch back to foo and merge it, and push it upstream

    git checkout foo
    git merge m
    git branch -d m
    git push


Usually you have some sort of concept of which branches are rebasable and which aren't. For example, I keep a fork of the canonical repository I work on, and do force-pushes to that all that I want.

Similarly the git development involves many throw-away branches, plus the "next" branch may get rebuilt every time there is a release.

People often say: "don't rewrite public history" but that's a simplification of: "don't rewrite public history unless people should have already known it was going to be rewritten"

If someone checks-out a branch from my private fork instead of from the official repo, they better not complain to me that I rebased it. Similarly if they checkout a branch named throwaway/test-integration-of-foo


Force pushing to your own remote is fine in my opinion, when making a pull-request -- necessary for our particular workflow (I originally created this for contributors on my project)

More needs to be written on this though, thanks for pointing it out


I follow this workflow:

1. Never do work on a branch that is being tracked on the origin. Always segregate your work on a local-only branch by doing a 'git checkout -b my-work'

2. Since I prefer not to have merge commits that don't add value to the history, I always get the latest changes, and rebase my-work off the latest. i.e.,

  git checkout develop (being tracked on the origin)
  git pull (get latest changes)
  git co my-work
  git rebase develop
  git co develop
  git merge my-work (no merge commit as it's fast forwarded)
  git push
  git branch -d my-work


> No warning on rebasing or amending pushed changes make this pretty unhelpful.

Btw, Mercurial Evolve makes this completely safe for hg. No more warnings about "git push -f"!


Yeah, this should rather read: "Never ever rebase pushed commits, unless you absolutely know what you are doing".


On undoing, fixing, or removing commits in git (Interactive help): http://sethrobertson.github.io/GitFixUm/fixup.html


This is dangerously vague.

Scenario: "When I try to push, I get an error message"

Answer: "...you must force push (-f) your changes"

A newbie could follow that advice and blow away their teammates' commits. Better advice would be to think twice and then consult someone with more experience before you even think of using git push -f.


I was disappointed that there was no mention of how to get out of the common problem situations when working in multi-user git projects.

Eg, you've done work on a branch, and then attempted to pull in recent updates from master, but now while trying to commit there are a huge number of changes listed that you don't recognize.

In my experience this is a sign you've done something wrong (merge instead of rebase?) and what you do next can cause a commit that undoes your colleagues recent work. It's a minor inconvenience and not a permanent loss, but it's a common mistake to make when you don't have experience with multi-user git projects.


Lots of good feedback in the comments, but this repository appears to be about 7 days old. I think it's fair to call it a work in progress, even if there's no disclaimer to that effect.


For combining more than 2-3 commits prior to pushing, in cases where you only want to end up with one commit, I find `git fetch; git reset --soft origin/master; git commit` to be quicker than interactive rebase.


> Flight Rules are the hard-earned body of knowledge recorded in manuals that list, step-by-step, what to do if X occurs, and why. Essentially, they are extremely detailed, scenario-specific standard operating procedures.

“Checklist” is the word for this. Checklists are widely used in aviation (they seem to have one for every case). I don't hear this term often in software engineering context, though Wikipedia says QA practices make use of checklists, too.


I'm grateful this post was made as it allowed me to find the NASA flight rules http://www.jsc.nasa.gov/news/columbia/fr_generic.pdf

However the commands are a little haphazard and as Gabe (gkop) mentions, not entirely safe.


Since you're using a flight metaphor, let's continue it: when doing things like this, use your instruments! It helps a lot to have gitk (or tig) open next to your shell when doing things like this. Git is a DAG editor, you can treat it as such with the proper visualization.


If you're using a rebase workflow this is much easier than interactively rebasing when you just want to squash the last N commits:

git reset --soft HEAD~N

This rolls back the history and places all the changes in those commits into staging. Commit with a new final message and off you go.


The author teaches git reset --hard without mentioning git reflog. That's evil.


Indeed ^_^ I'll try to add reflog as soon as I can, or pull-requests welcome!


Common issue worth adding: removing credentials committed to a repo.


To take a stab at this:

* If the credentials have already been written into shared history (e.g. merged into origin/master), regenerate the credentials ASAP. If the credentials are in local revisions only, use interactive rebase to edit the commit(s) in question.

* Introduce tooling to create better separation between dev and production credentials. Most automated tests should be able to run using bogus credentials. Pre-commit hooks can attempt to scan for accidental credential inclusion. Use a config system that loads credentials based on environment.


I really like the idea of "flight rules" to document common problems and codify how to resolve them. Does anyone know of any other good examples similar to this?


I found some of the wording a bit vague, I think diagrams or even short animations could have added clarity


Why is e.g. 'I need to combine commits' considered something that has gone wrong?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: