26

I have multiple active branches that I need to work on at the same time. Clearly I can create two working directories with a distinct branch per directory. Is that the only way to do it without having to "commit" and "checkout" in order to switch from one branch to another?

Richard
  • 10,122
  • 10
  • 42
  • 61

6 Answers6

22

If you are temporarily switching branches git stash is useful, however, remember that commits don’t need to persist forever; you may make temporary commits to roll back later.

So my recommendation is, if it is a many hours long switch, to do a git commit instead, because, depending on your memory, stashes can be easy to forget/lose/etc.

[In MyBranch]
>$ git commit -m "WIP: Stuff I was working on."
>$ git checkout AnotherBranch
[Do Stuff]
>$ git checkout MyBranch
>$ git reset HEAD^
[Continue]

And since this is a question about best practices, remember to give your stash a useful message using git stash save otherwise it can be difficult to find later.

cweider
  • 466
  • 2
  • 5
  • if you work in different PCs (eg: at office-location-1 and at office-location-2) by this way, u can commit your not-finalized work [at office-location-1] and push to remote, then later u can pull [at office-location-2] and reset it, do stuff and make a final-completed-commit. :) – kdaShivantha Aug 02 '19 at 07:00
20

Yes, though you can use git stash instead of commit if you're not ready to finalize your current work in progress.

dahlbyk
  • 75,175
  • 8
  • 100
  • 122
  • 1
    I was unaware of this command. i like it because it's exactly what I was thinking. Just a place to put my stuff until I was really ready to commit. In the last week I have committed "snap" several times so that I could change branches. It made me very mad because many of those changes are likely to change again... In the meantime these changes will become public to my team when I push... some of which might be embarrassing. "stash" is to be tested ASAP. Thanks! – Richard Jun 21 '10 at 02:22
  • 2
    Glad to help. It's important to realize, as cweider noted, that you can always rewrite your local history as long as a commit hasn't been pushed. For example, if you have a "snap" commit between other commits you want to keep, you could `cherry-pick` it into a different branch, then do a `rebase -i` to remove it from the other branch. – dahlbyk Jun 21 '10 at 13:08
5

git clone, through the local protocol, is a good alternative to be able to work on multiple branches at the same time.

I usually clone one local bare repo into multiple copies (one for each active branch), and use that bare repo as a central integration repo (since I can push easily to a bare repo, versus not being able to push to non-bare repo).

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • For the "bare repo" justification, see http://stackoverflow.com/questions/2041823/git-how-to-see-pulled-pushed-changes-in-origin/2041865#2041865 for instance – VonC Jun 16 '10 at 20:41
  • 2
    that's what people did with svn, now you can use git branching features, you don't need many local repositories. that's the main point of git. – Gismo Ranas Oct 23 '14 at 14:31
  • 4
    @GismoRanas I agree. I was writing this more than 4 years ago ;) – VonC Oct 23 '14 at 14:33
3

I got tired of switching between branches and so I wrote a smarter git checkout. Insert the following into your ~/.bash_profile, source it, and then simply use gch to switch to the last branch you were on.

current_git_branch() {
    git branch | grep \* | awk '{ print $2 }'
}
# a smart git checkout, with no args it switches to last branch.
gch() {
    if [ -n "$1" ]; then 
        echo `current_git_branch` >"/tmp/last_git_branch_used.txt"
        git checkout "$@"
    else
        if [ ! -f "/tmp/last_git_branch_used.txt" ]; then echo >&2 "ERROR: Please run gch with 1 argument first."
        else
            echo `current_git_branch` >"/tmp/last_git_branch_used.temp"
            git checkout `cat /tmp/last_git_branch_used.txt`
            mv "/tmp/last_git_branch_used."{temp,txt}
        fi
    fi
}
skensell
  • 1,421
  • 12
  • 21
  • Is this still how you'd approach the problem, a bit over a year later? Just curious because I was looking for exactly this. :) – Matt Passell Apr 16 '15 at 17:54
  • 1
    Yup, this exact snippet is still in my bash profile. One downside to this is that the `last_git_branch_used.txt` carries no information about the git repo, so if you're switching back and forth between different branches of different repos, this isn't so useful. But I still think I've saved a million keystrokes. – skensell Apr 25 '15 at 07:33
  • 2
    I've been using it for the past few days and finding it very handy. I do most of my work in one repo, so that's definitely a limitation I can live with. By the way, it works fine with zsh (which isn't surprising, since zsh is derived from bash). I'll share this with the rest of my team. Thanks! – Matt Passell Apr 27 '15 at 13:48
  • So I made some improvements to this script, that caches previously switched branches to the project's .git folder, regardless if you're in a subfolder or not. https://gist.github.com/spoike/3c84325b2dc35d18bbdf630606c7d034 – Spoike Dec 07 '16 at 14:09
  • 3
    Seems like you can switch to previously checked out branch with `git checkout -`, which is synonymous with `git checkout @{-1}`. You can read about [special cases for branch references in the git docs](https://git-scm.com/docs/git-checkout#git-checkout-ltbranchgt). – Spoike Dec 07 '16 at 14:26
1

If you are doing what is called branch-per-feature development as explained here:

http://martinfowler.com/bliki/FeatureBranch.html

you might want to also ensure that you switch the database schemas. Git can help in this by means of smudge and clean. Managing multiple databases locally is then possible. When you checkout a new branch, you smudge the connection string to annotate the database name with the branch name. Should the configuration file be committed at any point, it is cleaned by removing the name of the branch from the connection.

For more information, take a look at the Pro Git book.

user229044
  • 232,980
  • 40
  • 330
  • 338
Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
0

I have a bash function like this:

function gitredocommit {
  lastcomment=`git log | grep Date -A 2 -m 1 | tail -1 | sed -e 's/^ *//' -e 's/ *$//' | grep -v Merge`
  if [ -n "$lastcomment"  ]; then
    git reset --soft HEAD^; git add ../; git commit -m"$lastcomment"
  else
    echo "last commit was a merge, won't redo it"
  fi
}

You create a new branch, make a first (and last) commit and then with this you can do new stuff and overwrite this commit. If you need to update from the master you do it with

git rebase master

of course, so your commit is always on top in the branch. This works as long as you don't merge the branch in master.

Gismo Ranas
  • 6,043
  • 3
  • 27
  • 39
  • 1
    Is the `lastcomment=` line how you detect if a commit is a merge or not ?? – Andrew C Oct 23 '14 at 15:15
  • see the end of the line, use the magical horizontal scrollbar. – Gismo Ranas Oct 24 '14 at 13:25
  • Sorry, that was my attempt at saying "That's a completely insane way of detecting if something is a merge commit and it has horrible performance implications". Try using `git rev-parse HEAD^2` instead. – Andrew C Oct 24 '14 at 14:22
  • if it works, it works, it has not to be published on the annals of the academic experts of baloney computer science to be good. thank you for your suggestion anyway, I'll check how many pico-seconds performance I will gain with it. – Gismo Ranas Oct 27 '14 at 09:36
  • 2
    Except it doesn't work. You aren't detecting merge commits, you are detecting the word "Merge" and getting false positives and negatives. And if you do `git log` (without -1) on even a medium size project you are talking about wasting 10s of seconds to minutes. – Andrew C Oct 27 '14 at 14:12