70

This is a follow-up on this question on creating branches.

It strikes me as odd that I would still work on one repository because the files on my local machine will be a weird mix of different experiments.

I would imagine the best-practice method is to duplicate the repository and work in different folders on my computer for each branch -- but I don't know how to set this up. I have my current repository at Documents/San/CompProj so what are the commands I'd use to create a new repository tied to a different branch on a different local folder?

Git is fairly new to me so I'd love any corrections you can make on what I'm assuming/asking above.

Community
  • 1
  • 1
sscirrus
  • 55,407
  • 41
  • 135
  • 228
  • 8
    The thing that might be tripping you up is that if you don't commit a file to the repo before switching branches, git doesn't assume those changes are part of the rep/branch. Git doesn't keep track of uncommitted changes (other than to tell you they exist when you do git status--but they don't get automatically added to the repo) so when you switch branches the uncommitted changes are NOT replaced with whatever is in the new branch. Personally I wish Git would temporarily keep track of that just in this situation, but it does not – iconoclast Jun 22 '12 at 15:11
  • That will be possible with Git 2.5+ (Q2 2015) and `git checkout --to=`. See [my answer below](http://stackoverflow.com/a/30186607/6309) – VonC May 12 '15 at 09:18
  • 1
    Actually, the command will be `git worktree add []` (Git 2.5 rc2) – VonC Jul 13 '15 at 23:11

4 Answers4

51

As of Git 2.5, git-worktree directly supports this workflow. See VonC's answer to this question for details.

My answer below may suffice if you don't like git-worktree for whatever reason.


Git is designed to allow you to work within a single folder on disk. This is a single repository that contains all the branches you care about. You checkout whichever branch you want to work on at the time.

Within a Git repository, you can only have a single branch checked out at a time. If you check out a second branch, the files on disk are removed and replaced with those from the second branch.

If you have the following branches:

BRANCH-A        BRANCH-B
alpha.txt       alpha.txt
bravo.txt
charlie.txt     charlie.txt
                delta.txt

When you're on branch-A and you checkout branch-B, then bravo.txt will be removed and delta.txt will be added to your working directory.

However, git-checkout will not overwrite changes you've made to files unless you supply the -f argument. If you make a change to alpha.txt then try to switch to branch-B, you'll get a message warning you that your changes would be lost and aborts the checkout.

The exceptions are untracked files. If you have branch-A checked out and you create a new file called echo.txt, Git will not touch this file when you checkout branch-B. This way, you can decide that you want to commit echo.txt against branch-B without having to go through the hassle of (1) move the file outside the repo, (2) checkout the correct branch, and (3) move the file back into the repo.


Footnote

Actually, Git doesn't force you to use a single working directory. If you want, nothing is stopping you from creating different paths on disk for each branch you want to work on.

/home/me/project
 +-- branch-a/
 +-- branch-b/
 +-- ...

Each of these paths is its own Git repository (each one has a .git folder inside), and you can push and pull commits between the repos.

cd ~/project                     ## Go to my projects directory
git clone branch-a branch-b      ## Create a new branch-b

cd branch-b
 ... work work work ...
git commit -a -m "Made some changes on branch-b"

git pull origin                  ## Fetch and merge the changes from branch-a
git push origin                  ## Push my changes back to branch-a

This is how some people use Mercurial if they aren't using named branches: they clone the repository into a new directory on disk for each branch they want, then push and pull changesets between them.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Stephen Jennings
  • 12,494
  • 5
  • 47
  • 66
  • Stephen - this is helping a lot, thank you! This is tripping me up: I changed a file in branch 1 and did `git add public/test.html`. I assume this would make it like your `bravo.txt` but when I check out a different branch it's still there. How do I tie `public/test` exclusively to branch 1? – sscirrus Dec 12 '11 at 06:52
  • @sscirrus: If `public/test.html` had already been added and committed, and your added changes remained when you switched, then that file is currently the same in both branches. This is more like `alpha.txt` in the example. When the committed version of a file is the same in both branches, Git saves you some trouble and keeps your changes when switching branches. You can un-add your changes by running `git reset public/test.html`. – Stephen Jennings Dec 12 '11 at 07:04
  • 3
    @sscirrus Note that it's the **`commit`** which puts the files "into" the branch. The `add` by itself is just a way of preparing (or "staging") the files for the commit. – Gareth Dec 12 '11 at 07:22
  • @Gareth - That was the missing link, thank you! I'm going to work on this a little more and make sure it's working as expected. – sscirrus Dec 12 '11 at 07:27
  • This used to be a great answer. But recently, git has started supporting multiple working trees (and did before that too, via some script-fu). Maybe you should consider linking to the other (newer) answer in your own, so people notice it? – ArjunShankar Feb 25 '16 at 11:56
41

With Git 2.5+ (Q2 2015), Git is no longer designed to work within a single folder (ie a single working tree)

Git will support multiple working trees (for one cloned git repo) with the new command git worktree add <path> [<branch>].

That replaces an older script contrib/workdir/git-new-workdir, with a more robust mechanism where those "linked" working trees are actually recorded in the main repo new $GIT_DIR/worktrees folder (so that work on any OS, including Windows).

You will be able to checkout different branches in different path while being part of the same main cloned repo.

See more at "Multiple working directories with Git?"

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Suppose I just want to edit one file. Does git worktree make an entire second copy of the entire repo just for that? Is there any way to tell git "psuedo-copy this repo, make everything symlinks (or hard links) until I modify stuff"? –  Nov 23 '16 at 22:30
  • Yes, except if you try combining sparse checkout to git worktree (not sure if it is possible though). – VonC Nov 23 '16 at 22:32
  • I remember SCCS (and maybe RCS) let you check out older version files as "filename#v17" or something and you could merge them back into your current file when ready. I take it git has nothing like that? Can I make a copy of a file, tweak it, and then merge it back into the original? Or is that more a diff thing? –  Nov 24 '16 at 05:14
  • @barrycarter More precisely: http://stackoverflow.com/a/11593308/6309 (checkout --patch) – VonC Nov 24 '16 at 05:17
4

Your concern about 'the files on my local machine will be a weird mix of different experiments.' is unfounded - if you have branch 2 checked out, you will not see the files of branch 1 at the same time.

I would do something like

# on master branch
git checkout master
# Create a branch for feature 1
git checkout -b feature_1
# work on feature 1

# Start a new feature branch
git checkout master
git checkout -b feature_2
# work on feature 2

# feature 2 finished and committed, time to merge 
git checkout master
git merge feature_2

# update feature_1 branch
git checkout feature_1
git merge master
I82Much
  • 26,901
  • 13
  • 88
  • 119
  • Does that mean that whenever I type `git checkout x` it literally changes the files that are sitting on my machine and it changes what I would see in TextMate? – sscirrus Dec 12 '11 at 05:53
  • I tried creating a file in my repo while in Master, then I checked out feature_1 and the file still existed in my local filesystem. It seems from this that if I create/edit files in my folder for one branch then check into another, my changes will still be sitting on my local filesystem in the same folder. Am I missing something? – sscirrus Dec 12 '11 at 06:02
  • If you create the file in branch one and add it to that repo (git add, git commit), and then you switch to a different branch, you should not see that file – I82Much Dec 12 '11 at 06:04
  • Yes. "Behind the scenes," files are copied into and out of the "invisible" .git directory in your project's root, but don't worry about that. When you run git checkout x, etc., the files that you (and TextMate) see all change on disk. – Bob Gilmore Dec 12 '11 at 06:04
  • 2
    This is not simultaneously. – rafaelvalle Nov 20 '17 at 00:44
1

I suggest my solution via small script https://web.archive.org/web/20141114201917/http://www.redhotchilipython.com/en_posts/2013-02-01-clone-per-feature.html

While git stash tools are nice, I find having multiple clones much better. You can run tests in one branch, while work on other. Or you don't even have to stop debugger, close editor, clean tempfiles or something else.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Konstantine Rybnikov
  • 2,457
  • 1
  • 22
  • 29