I'm not sure if this is something supported by Git, but in theory it seems like it should work to me.
My workflow often involves my editing of files in multiple branches simultaneously. In other words, I often want to open a few files in one branch is while I edit the contents of another file in another branch.
My typical solution to this is to make two checkouts, but it's a shame I can't share branches and refs between them. What I would like is to just have two working directories managed by the same .git folder.
I'm aware of local git clone solutions (the default, which is to hardlink shared objects, and the --shared option, which sets up an alternate object store with the original repo), but these solutions only cut down on disk space usage, and especially in the case of --shared, seem fraught with peril.
Is there a way to use one .git folder, and have two working directories backed by it? Or is Git hardcoded to have just one working directory checked out at any time?
The
git
distribution comes with a contributed script calledgit-new-workdir
. You would use it as follows:where project-dir is the name of the directory containing your
.git
repository. This scripts creates another `.git' directory with many symlinks to the original one except for files that cannot be shared (like the current branch), allowing you to work in two different branches.It sounds a bit fragile, but it's an option.
The only solution I can think of is to clone two directories and add them as remote repositories of each other. You can then keep pulling stuff from the changed one into the other without actually pushing anything to the remote repository.
I am assuming you want to have two working directories and not two clones of the remote because you don't want to push some branches to the remote. Otherwise, two clones of your remote would work just fine - you just need to do some pushes and pulls to keep all three in sync.
Git 2.5 proposes since July 2015 a replacement for
contrib/workdir/git-new-workdir
: git worktreeSee commit 68a2e6a by Junio C Hamano (
gitster
).The release note mentions:
See commit 799767cc9 (Git 2.5rc2)
That means you now can do a
git worktree add <path> [<branch>]
Warning: there is still a
git worktree
"BUGS" section to be aware of.Note: with git 2.7rc1 (Nov 2015) you are able to list your worktrees.
See commit bb9c03b, commit 92718b7, commit 5193490, commit 1ceb7f9, commit 1ceb7f9, commit 5193490, commit 1ceb7f9, commit 1ceb7f9 (08 Oct 2015), commit 92718b7, commit 5193490, commit 1ceb7f9, commit 1ceb7f9 (08 Oct 2015), commit 5193490, commit 1ceb7f9 (08 Oct 2015), commit 1ceb7f9 (08 Oct 2015), and commit ac6c561 (02 Oct 2015) by Michael Rappazzo (
rappazzo
).(Merged by Junio C Hamano --
gitster
-- in commit a46dcfb, 26 Oct 2015)For instance:
Note: if you MOVE a worktree folder, you need to manually update the
gitdir
file.See commit 618244e (22 Jan 2016), and commit d4cffffd6 (18 Jan 2016) by Nguyễn Thái Ngọc Duy (
pclouds
).Helped-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit d0a1cbc, 10 Feb 2016)The new doc in git 2.8 (March 2016) will include:
Be careful when deleting a branch: before git 2.9 (June 2016), you could delete one in use in another working tree.
See commit f292244 (29 Mar 2016) by Kazuki Yamaguchi (
rhenium
).Helped-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit 4fca4e3, 13 Apr 2016)Similarly, before git 2.9 (June 2016), renaming a branch checked out in another worktree did not adjust the symbolic HEAD in said other worktree.
See commit 18eb3a9 (08 Apr 2016), and commit 70999e9, commit 2233066 (27 Mar 2016) by Kazuki Yamaguchi (
rhenium
).(Merged by Junio C Hamano --
gitster
-- in commit 741a694, 18 Apr 2016)The locking mechanism is officially supported with git 2.10 (Q3 2016)
See commit 080739b, commit 6d30862, commit 58142c0, commit 346ef53, commit 346ef53, commit 58142c0, commit 346ef53, commit 346ef53 (13 Jun 2016), and commit 984ad9e, commit 6835314 (03 Jun 2016) by Nguyễn Thái Ngọc Duy (
pclouds
).Suggested-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit 2c608e0, 28 Jul 2016)Git 2.13 (Q2 2017) add a
lock
option in commit 507e6e9 (12 Apr 2017) by Nguyễn Thái Ngọc Duy (pclouds
).Suggested-by: David Taylor (
dt
).Helped-by: Jeff King (
peff
).(Merged by Junio C Hamano --
gitster
-- in commit e311597, 26 Apr 2017)So
git worktree add' --lock
is the equivalent ofgit worktree lock
aftergit worktree add
, but without race condition.Git 2.17+ (Q2 2018) adds
git worktree move
/git worktree remove
: see this answer.Git 2.19 (Q3 2018) add a "
--quiet
" option to make "git worktree add
" less verbose.See commit 371979c (15 Aug 2018) by Elia Pinto (
devzero2000
).Helped-by: Martin Ågren , Duy Nguyen (
pclouds
), and Eric Sunshine (sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit a988ce9, 27 Aug 2018)I came across this question hoping for a solution I didn't find here. So now that I did find what I needed, I decided to post it here for others.
Caveat: This is probably not a good solution if you need to edit multiple branches simultaneously, like OP states. It is for having multiple branches checked out simultaneously that you don't intend to edit. (Multiple working directories backed by one .git folder.)
There were a few things I've learned since I came to this question the first time:
What a "bare repository" is. It is essentially the contents of the
.git
directory, without being located in a working tree.The fact that you can specify the location of the repo you are using (the location of your
.git
dir) on the command line with thegit
option--git-dir=
The fact that you can specify the location of your working copy with
--work-tree=
What a "mirror repo" is.
This last is a pretty important distinction. I don't actually want to work on the repo, I just need to have copies of different branches and/or tags checked out simultaneously. In actual fact, I need to guarantee that the branches don't end up different from my remote's branches. So a mirror is perfect for me.
So for my use case, I got what I needed by doing:
The big caveat about this is that there isn't a separate HEAD for the two copies. So after the above, running
git --git-dir=<localgitdir> --work-tree=firstcopy status
will show all the differences from branch2 to branch1 as uncommitted changes - because HEAD is pointing at branch2. (That's why I use the-f
option tocheckout
, because I'm not actually planning to make any changes locally at all. I can checkout any tag or branch for any work-tree, as long as I use the-f
option.)For my use case of having multiple checkouts co-existing on the same computer without needing to edit them, this works perfectly. I don't know if there is any way to have multiple HEADs for the multiple work trees without a script such as is covered in the other answers, but I hope this is helpful to someone else anyway.