Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

    git tag -s 5.0.0.0		# Create a gpg-signed tag

You can use -m MSG with -a to save starting an editor. N.b you must use -a or -s otherwise git describe will ignore your tag.

Then

    git log --graph --decorate	# See the tag you just made
    git push --tags			# Push all your tags upstream

Oops, I should have done that on a ticket branch

Adpted from  http://schacon.github.com/git/git-reset.html

I thought it was going to be a tiny bug-fix that I could commit straight to master but it grew into something that should be done on a ticket: (This is for when you have already git committed the changes, but not git pushed them.)

    $ git checkout master
    Already on 'master'
    Your branch is ahead of 'origin/master' by 5 commits.

(Remember that number 5:)

If you're making a new ticket for this fix,

    $ git branch feature/OPSIM-221
    $ git reset --hard HEAD~5
    $ git checkout feature/OPSIM-221

        and keep working as usual.

        If you want to apply your commits to an existing ticket branch,

    $ git branch temp
    $ git reset --hard HEAD~5
    $ git checkout feature/OPSIM-221
    $ git merge temp
    $ git branch -d temp

        (but this will also merge all other commits to master into your ticket branch).

Some useful command-line prompt hacking

git is distributed with a shell script, contrib/completion/git-prompt.sh, that defines a function, __git_ps1 that's useful for displaying the branch and status of a git repository in your command-line prompt. This file seems to be generally installed by distributors, and so you probably already have __git_ps1 defined in your environment. If not, grab that shell script and source it. If you can't get it, or don't want it, then a poor-man's version is supplied, below.

The behaviour of __git_ps1 is configurable with the following environment variables: GIT_PS1_SHOWDIRTYSTATE (define to non-empty value; then * indicates unstaged changes and + indicates staged changes), GIT_PS1_SHOWSTASHSTATE (define to non-empty value; then $ indicates non-empty stash), GIT_PS1_SHOWUNTRACKEDFILES (define to non-empty value; then $ indicates the presence of untracked files) and GIT_PS1_SHOWUPSTREAM (define as auto; then < indicates you're behind the upstream and can merge, > indicates you're ahead of the upstream and can push, <> indicates you've diverged, and =indicates there's no difference).

The result is something like:

    user@machine:~/LSST/afw (tickets/1234>) $ 

(i.e., I'm on branch tickets/1234 with changes committed that I can push) but all you have to do is add $(__git_ps1) at the desired location in your current PS1 definition.

So, here's what I use:

    # The following two functions provide a basic alternative for git.git/contrib/completion/git-prompt.sh
    # in case it's not available
    function prompt_git_dirty {
        local gitstat=`git status 2> /dev/null`
        local charstat=""
        [[ -z $(echo $gitstat | grep "nothing to commit") ]] && charstat="\%"
        [[ -n $(echo $gitstat | grep "Your branch and '.*' have diverged") ]] && echo "${charstat}\<\>" && return
        [[ -n $(echo $gitstat | grep 'Your branch is ahead of') ]] && echo "${charstat}\>" && return
        [[ -n $(echo $gitstat | grep 'Your branch is behind') ]] && echo "${charstat}\<" && return
        echo $charstat
    }
    function prompt_git_branch {
      git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/[\1$(prompt_git_dirty)]/"
    }

    # Setup for git.git/contrib/completion/git-prompt.sh
    export GIT_PS1_SHOWDIRTYSTATE=1
    export GIT_PS1_SHOWSTASHSTATE=1
    export GIT_PS1_SHOWUNTRACKEDFILES=1
    export GIT_PS1_SHOWUPSTREAM="auto"
    type __git_ps1 1>/dev/null 2>&1 || alias __git_ps1=prompt_git_branch

    PS1='\[\e[1;32m\]\u@\h\[\e[0;39m\]:\[\e[1;34m\]\w\[\e[1;31m\]$(__git_ps1)\[\e[0;1m\] \$ \[\e[0;39m\]'

...

See  this great explanation here, that I didn't find until I wrote the text below (sigh)...

Committing changes to a git repository is a two-step process:

    • Step 1: specify which of the (possibly many) modified files would you like to commit as a part of this change set
    • Step 2: execute the commit.

The two above steps equate to the following commands:

    • Step 1: git add modifiedFile1.cc modifiedFile2.cc modifiedFile3.cc ...
    • Step 2: git commit

Most version control systems (including SVN and hg) omit Step 1. and always assume you want to commit all files that have been modified. Git is not as presumptuous, because there are sometimes good reasons why you'd want to split the modifications into two different commits (e.g., if you've modified 10 files while developing a new feature, while the one-line modification in the 11th file was an unrelated bug that you stumbled upon and fixed in the process). Now, what if you do want to commit changes to all modified files (or if you're used to SVN behavior and see no point in extra typing)? Then use:

    • git commit -a

The '-a' switch tells git to run an implicit git add for all modified files in the working directory, before performing the commit.

How do I restore a file to unmodified state ?

    git checkout HEAD myfile.txt

The way to read this command is: 'Dear git, please check out from branch HEAD the file myfile.txt'. In git, HEAD always refers to the current branch. You can probably already tell that if I wrote git checkout otherbranch myfile.txt git would check out the file from otherbranch. It's even more general than that: instead of a branch name, you can give it any  tree-ish out of which to extract the file.

What are best practices for developing on a branch?

Often the features you're developing take a long time to mature. Therefore your feature branch (also sometimes called a "topic branch") may lag behind master quite a lot by the time you're done. What should you do? Should you "sync up" often by merging 'master' into your feature branch, or should you wait and fix any conflicts until the very end?

Junio Hamano has  an excellent post on this that is a MUST to read. To summarize:

    • Merge your feature branch into the master only when it's complete (up to bugfixes).
    • Merge the master into your feature branch only when there's a new feature in master that the code in your branch needs to use

This strategy minimizes the number of merges in the history of the project, which helps with tools like 'git bisect' (automated finding of commits that caused bugs/regressions). And if you're nervous about doing all the conflict resolution at the very end, look into  git rerere.

What are 'cache', 'index', and 'staging area'?

To first (and second, and probably third) order, they're the same: the staging area where you place the files (using 'git add') that are to be a part of the next commit. That there are three terms for one and the same thing is a  historical artefact.

I'm having problems with 'git push' and 'non-fast-forward mege' errors

See if this answers your question.

How can I avoid stepping on people's toes when making changes?

See this page on interacting with gits.