Tales of the TeenyTyper #2 – The git CPAP trap!

I currently class myself as a novice in distributed git repositories. In my extant work role, I’m using git for source version control, but I’m operating as a git project user group of one,  as my supervisor refuses to use any form of source control other than simply copying the entire source folder.

Being rather pragmatic about it all, I kept our git setup as simple as the situation needed.  I’ve gotten by just fine with a single repository on my work machine with a branch per developer that I can occasionally merge and redistribute from.

One of the things I’m learning out of my TeenyTyper experience is how to use distributed git repositories for my project via GitHub.  My early experiments have been making a mess of the commit history (no, don’t look!).

The problems started not long after I took my clone of the TeenyTyper repository hosted with GitHub.  I couldn’t push my recent commit back to GitHub, despite the fact that all I’d read had  me believing that I should be able to.  I eventually worked around it by doing a merge of the remote repository into the local repository.  The merged version I could push successfully back to GitHub. This seemed to happened rather non-deterministically, and irked me because I shouldn’t actually need to merge these changes.

I went pouring through the git manual this morning, and now I see what I was doing to make all that mess. It makes sense now that I see the process, but as a novice I missed initially what I was doing to cause the issues in the first place.

The essence of my problem was that I was doing the following sequence of activities:

  1. (change some repository managed files locally)
  2. git add <changed files>
  3. git commit
  4. git push <remote-repository> <local-repository>
  5. (some more changes forgotten in the first commit)
  6. git commit –amend
  7. git push <remote-repository> <local-repository>

The error returned looks something like this:

To git@github.com:user/repo.git
! [rejected] branchname -> branchname (non-fast forward)
error: failed to push some refs to 'git@github.com:user/repo.git'

I see now that a “commit amend” does not modify an existing git commit object, it replaces that commit object with an entirely new one, based on the old. You can confirm this for yourself easily simply by looking at the commit hash before and after the amend.  The second push attempt fails  because there is no common base for the two repositories to base the push on, as that original commit was replaced (only) locally by the “commit amend”.

My take-away lesson from all this is to self-censor any attempts at amending commits that have been sent off already to a remote repository. The convenience of tweaking a commit with an amend is just not worth the effort that I need to go through to get the repositories back on the same page.

It’s a trap, and it’s triggered by the sequence of (C)ommit, (P)ush, (A)mend, (P)ush git commands.  I’m now wishing they’d called a “commit amend” a “commit replace” to better mesh with my intuition on the  meaning of amend.  Ah well, we live and learn.

Push git commits long and prosper!


2 responses to “Tales of the TeenyTyper #2 – The git CPAP trap!

  1. There’s another rule that goes along the lines of never rebasing something that has been pushed to the public, for the exact same reason. Anyone who has pulled might have the common commit disappeared from under them.

    The only time I would consider rebasing is when I’m contributing a patch to another project, and want to merge all my mini commits as one large one, before pushing out to github, and then requesting a pull on the original project.

    I guess the other situation is if you’re working on an alpha, it’s not ready for github, or you’ve made a right pudding of the commit history, and want to tidy it up, before doing the push to github.

    (C)ommit, (R)ebase, and eventually (P)ush might become the rule. It can be hard to follow if your remote repository is also a part of your backup plan , where the remote repository is the beast getting backed up.

    With regards to the git push command, if I have tracking set up, I can usually get away with “git push” by itself. However, sometimes I don’t have master set up to track the origin, in which case the command becomes “git push “.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s