Skip to contentSkip to conversation

Git branches - confusing behavior

DISCUSSION Dima Kagan 9 participants 19 messages Jun 15, 2016 2 messages not in the archive

lore
Share & tools
lore

Dima Kagan

author
#0 lore raw

Hi,

I'm currently evaluating git for doing some local work without depending on the main subversion server. I started with the following steps:

Quoted 5 lines

git-svn clone http://svn.test.org/test/trunk
cd trunk
git branch test_branch
git checkout test_branch
vi somefile

Now, when I run 'git status' I get:
# On branch test_branch
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

This is what I expect of course. However, when I execute 'git checkout master', I get:
M somefile
Switched to branch "master"

And after running 'git status' on master I get:
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

Thanks in advance!

#1 lore raw
Quoted 10 lines · Dima Kagan

I'm currently evaluating git for doing some local work without depending on the main subversion server. I started with the following steps:

Quoted 5 lines

git-svn clone http://svn.test.org/test/trunk
cd trunk
git branch test_branch
git checkout test_branch
vi somefile

Quoted 8 lines

Now, when I run 'git status' I get:
# On branch test_branch
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

And now you have 'somefile' in the working arew, which state isn't saved anywhere git knows of.

Quoted 4 lines

This is what I expect of course. However, when I execute 'git checkout master', I get:
M somefile
Switched to branch "master"

Git tries hard to preserve your modifications. If you don't want to commit changes to test_branch, you can use git-stash to stash them away.

Note that the above is possible only in the trivial merge case. Otherwise you would need to use "git checkout -m" (to merge), or "git checkout -f" (to force checkout, possibly losing changes).

Quoted 9 lines

And after running 'git status' on master I get:
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

This is normal, and wanted, behavior.

Signature · 3 lines
Jakub Narebski
Poland
ShadeHawk on #git
author
#2 lore raw
Quoted 28 lines · Jakub Narebski
Quoted 9 lines · Dima Kagan

I'm currently evaluating git for doing some local work without depending on the main subversion server. I started with the following steps:

Quoted 5 lines

git-svn clone http://svn.test.org/test/trunk
cd trunk
git branch test_branch
git checkout test_branch
vi somefile

Quoted 8 lines

Now, when I run 'git status' I get:
# On branch test_branch
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

And now you have 'somefile' in the working arew, which state isn't saved anywhere git knows of.

Quoted 4 lines

This is what I expect of course. However, when I execute 'git checkout master', I get:
M somefile
Switched to branch "master"

Quoted 8 lines

Git tries hard to preserve your modifications. If you don't want to commit changes to test_branch, you can use git-stash to stash them away.

Note that the above is possible only in the trivial merge case. Otherwise you would need to use "git checkout -m" (to merge), or "git checkout -f" (to force checkout, possibly losing changes).

So if I am working on more than one branch at a time I need to commit my changes every time before I do 'git checkout <branch>'?

Quoted 9 lines
Quoted 9 lines

And after running 'git status' on master I get:
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: somefile
#
no changes added to commit (use "git add" and/or "git commit -a")

Quoted 9 lines
Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

This is normal, and wanted, behavior.

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

#3 lore raw
Quoted 2 lines · Dima Kagan
Quoted 1 line · Jakub Narebski

Dima Kagan <[email protected]> writes:

[...]

Quoted 2 lines

So if I am working on more than one branch at a time I need to commit my changes every time before I do 'git checkout <branch>'?

[...]
Not necessary, see below (and it is not necessary bad).

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

This is normal, and wanted, behavior.

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

How would you want git to behave, with "git checkout <branch>" changing branches _in place_, in single working area? Besides, current behavior, together with "git checkout -m" option, allows to change branches when you have realized (after making some changes) that you are on wrong branch...

There are few possible solutions:

1. Save state before switching branches

1.1. You can simply commit changes before switching branch, perhaps with "(WIP)" (work in progress) in the commit message. Then, when you go back to the branch, you can continue your work, and simply --amend (as in "git commit --amend" a commit.

1.2. You can use git-stash to save state of your working area (working directory) _and_ index, change branches, and when going back to branch restore state using "git stash apply". I think you can save state even during not resolved merge.

1.3. If you use patch management interface on top of Git, like StGit (or Guilt), you can simply "stg refresh" a patch, then change branches. When returning to branch, use refresh and/or edit, then create new patch if you think current is finished (you can always go back...).

2. Use separate working for differen branches: this is what Bazaar does, what Mercurial does by default without 'localbranch' extension, and I
think also what Subversion does. Take a look at contrib/workdir
on how to manage multiple working areas with single repository; the core.workdir and --working-dir could also be of help.

Note that in this case you have to take care to not have the same branch checked out to two (or more) different working areas, to not stomp on your changes, and to avoid confusion.

Final note: you would work better learning SCM "the git way", and not to rely on Subversion bad habits (yes, I know that bad CVS habits are worse...) ;-)

Signature · 2 lines
Jakub Narebski
Poland
#4 lore raw
In reply to Dima Kagan
Quoted 1 line · Dima Kagan

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

If you *really* want SVN's behaviour of "branches", just copy your whole working tree (including the .git directory) and start making changes in that. Then they'll be completely separate and you can just 'cd' between them.

Dave.

author
#5 lore raw
Quoted 11 lines · David Symonds
Quoted 1 line · Dima Kagan

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

If you *really* want SVN's behaviour of "branches", just copy your whole working tree (including the .git directory) and start making changes in that. Then they'll be completely separate and you can just 'cd' between them.

Dave.

What's the point of using git then? :) I like the way branches are created and switched in git, but I would like each branch to preserve it's own history of modifications. Is that too much to ask? :)

#6 lore raw
Quoted 11 lines · Dima Kagan
Quoted 10 lines · David Symonds
Quoted 1 line · Dima Kagan

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

If you *really* want SVN's behaviour of "branches", just copy your whole working tree (including the .git directory) and start making changes in that. Then they'll be completely separate and you can just 'cd' between them.

Quoted 3 lines
Quoted 1 line

Dave.

What's the point of using git then? :) I like the way branches are created and switched in git, but I would like each branch to preserve it's own history of modifications. Is that too much to ask? :)

Preserving history is called "committing", which is how git branches preserve their own history. You said you don't want to commit changes. You can't have it both ways. :-P

Dave.

author
#7 lore raw
Quoted 12 lines · Dima Kagan
Quoted 11 lines
Quoted 10 lines · David Symonds
Quoted 1 line · Dima Kagan

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

If you *really* want SVN's behaviour of "branches", just copy your whole working tree (including the .git directory) and start making changes in that. Then they'll be completely separate and you can just 'cd' between them.

Dave.

Quoted 8 lines
Quoted 1 line

What's the point of using git then? :) I like the way branches are created and switched in git, but I would like each branch to preserve it's own history of modifications. Is that too much to ask? :)

Preserving history is called "committing", which is how git branches preserve their own history. You said you don't want to commit changes. You can't have it both ways. :-P

Dave.

Not quite. :) The current branch knows what files have been modified without committing the changes. Why should other branches be aware of these changes until I commit them?

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#9 lore raw
Quoted 16 lines · Dima Kagan
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

This is normal, and wanted, behavior.

That's a subjective point of view :) I'm coming from the SVN world and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

There are several ways, actually.

Quoted 8 lines

The one I prefer to use is to commit the modifications. Then, you can use git-reset HEAD^ to drop that temporary commit when you come back to this branch, or git-commit --amend to modify it.

Always keep in mind that in git's world, history is not set in stone, you can always modify previous commits, reorder them or merge them, as long as you have not pushed them to your public repository (in your case, the SVN one).

Hi!
Thanks for these little tips.

I understand that git is very powerful, however some things are hard to grasp when switching from SVN. Perhaps I should overview my workflow to see how it can benefit from git, despite these differences.

#10 lore raw
In reply to Dima Kagan
Quoted 11 lines · Dima Kagan
Quoted 9 lines
Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

This is normal, and wanted, behavior.

That's a subjective point of view :) I'm coming from the SVN world

and uncommitted changes on one branch don't affect other branches. Is there a way I can achieve this behavior with git?

There are several ways, actually.

The one I prefer to use is to commit the modifications. Then, you can use git-reset HEAD^ to drop that temporary commit when you come back to this branch, or git-commit --amend to modify it.

Always keep in mind that in git's world, history is not set in stone, you can always modify previous commits, reorder them or merge them, as long as you have not pushed them to your public repository (in your case, the SVN one).

author
#11 lore raw
In reply to Jakub Narebski
Quoted 7 lines
Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

I just realized that this behavior is even more confusing.
If I commit the file on 'test_branch' and only then 'git checkout master' the changes are not visible on 'master' until I merge. So why should 'master' be affected by uncommitted changes on some branch???

#12 lore raw
Quoted 4 lines · Dima Kagan
Quoted 4 lines
Quoted 4 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Quoted 8 lines
Quoted 3 lines
Quoted 2 lines

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

I just realized that this behavior is even more confusing. If I commit the file on 'test_branch' and only then 'git checkout master' the changes are not visible on 'master' until I merge. So why should 'master' be affected by uncommitted changes on some branch???

Uncommitted changes are not on any branch, they are in your working tree and/or your index. And actually, SVN does the exact same thing.

# Create a SVN repository with trunk/ and branches/ # ----

$ mkdir svn
$ cd svn
$ svnadmin create repo
$ export REPO="file://$PWD/repo"
$ svn co $REPO wc
Checked out revision 0.
$ cd wc
$ svn mkdir trunk branches
A         trunk
A         branches
$ svn commit -m init
Adding         branches
Adding         trunk

Committed revision 1.

$ svn switch $REPO/trunk
D    trunk
D    branches
Updated to revision 1.

# Create some content in trunk
# ----

$ echo 123 > testfile
$ svn add testfile
A         testfile
$ svn commit -m test
Adding         testfile
Transmitting file data .
Committed revision 2.

# Create a branch
# ----

$ svn cp $REPO/trunk $REPO/branches/b1 -m branch

Committed revision 3.

# Produce some uncommitted changes on trunk
# ----

$ echo 456 > testfile
$ svn st
M      testfile
$ svn diff
Index: testfile
===================================================================
--- testfile    (revision 2)
+++ testfile    (working copy)
@@ -1 +1 @@
-123
+456

# Switch to the branch
# ----

$ svn switch $REPO/branches/b1
At revision 3.
$ svn st
M      testfile
$ svn diff
Index: testfile
===================================================================
--- testfile    (revision 3)
+++ testfile    (working copy)
@@ -1 +1 @@
-123
+456

The uncommitted changes survived the branch change and are still in the working tree, in svn just like in git.

Björn

author
#13 lore raw
Quoted 87 lines · Björn Steinbrink
Quoted 10 lines · Dima Kagan
Quoted 6 lines
Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

I just realized that this behavior is even more confusing. If I commit the file on 'test_branch' and only then 'git checkout master' the changes are not visible on 'master' until I merge. So why should 'master' be affected by uncommitted changes on some branch???

Uncommitted changes are not on any branch, they are in your working tree and/or your index. And actually, SVN does the exact same thing.

# Create a SVN repository with trunk/ and branches/ # ----

$ mkdir svn
$ cd svn
$ svnadmin create repo
$ export REPO="file://$PWD/repo"
$ svn co $REPO wc
Checked out revision 0.
$ cd wc
$ svn mkdir trunk branches
A         trunk
A         branches
$ svn commit -m init
Adding         branches
Adding         trunk

Committed revision 1.

$ svn switch $REPO/trunk
D    trunk
D    branches
Updated to revision 1.

# Create some content in trunk
# ----

$ echo 123 > testfile
$ svn add testfile
A         testfile
$ svn commit -m test
Adding         testfile
Transmitting file data .
Committed revision 2.

# Create a branch
# ----

$ svn cp $REPO/trunk $REPO/branches/b1 -m branch

Committed revision 3.

# Produce some uncommitted changes on trunk
# ----

$ echo 456 > testfile
$ svn st
M      testfile
$ svn diff
Index: testfile
===================================================================
testfile (working copy) renamed from testfile (revision 2) +1 -1
@@ -1 +1 @@
-123
+456

# Switch to the branch
# ----

$ svn switch $REPO/branches/b1
At revision 3.
$ svn st
M      testfile
$ svn diff
Index: testfile
===================================================================
testfile (working copy) renamed from testfile (revision 3) +1 -1
@@ -1 +1 @@
-123
+456
Quoted 4 lines

The uncommitted changes survived the branch change and are still in the working tree, in svn just like in git.

Björn

Yes, I am aware of that, except one rarely works in one directory on multiple svn branches, because the branches are not private. Git's branches can be private, so perhaps this behavior should be different from SVN?

BTW, Is there a way to do 'svn checkout -b new_branch' into a new directory?

#14 lore raw
Quoted 8 lines · Dima Kagan
Quoted 7 lines · Björn Steinbrink
Quoted 6 lines · Dima Kagan
Quoted 6 lines
Quoted 6 lines

Basically I see that the same file I edited on the 'test_branch' branch appears to be modified on the 'master' branch as well. This behavior is unwanted, of course.

Can someone please tell me, what am doing wrong? Or is this git's normal behavior?

Quoted 7 lines
Quoted 7 lines
Quoted 4 lines

I just realized that this behavior is even more confusing. If I commit the file on 'test_branch' and only then 'git checkout master' the changes are not visible on 'master' until I merge. So why should 'master' be affected by uncommitted changes on some branch???

Uncommitted changes are not on any branch, they are in your working tree

[example removed]

Quoted 7 lines
Quoted 4 lines

The uncommitted changes survived the branch change and are still in the working tree, in svn just like in git.

Yes, I am aware of that, except one rarely works in one directory on multiple svn branches, because the branches are not private.

I always did that, the working copy _is_ private even in svn, so messing with that was not a problem there either.

Quoted 2 lines

Git's branches can be private, so perhaps this behavior should be different from SVN?

No. Uncommitted changes are, well, uncommitted. They don't belong to any branch yet. A branch is not some structure that contains history in itself. A branch just points to a commit, and the commits, with their parent-child relations, form the actual history. The index and working tree are not part of a branch.

Changing that would even break a workflow that is rather common for me. I start working on something that is either just experimental or assumed to be a very small change. Then I realize that the change is worth keeping and/or too big and deserves its own branch. At that point, I can just do "git checkout -b new_branch", and pretend that I started working on that branch right from the start. With your proposed change, I would need some extra command to transfer the work in progress from the old branch to the new branch.

If I ever want to switch to another branch and not keep the changes in my working tree and index, I stash them away or create a temporary commit, which I later amend. That's a use-case that comes up rather seldom though (for me at least).

Quoted 1 line

BTW, Is there a way to do 'svn checkout -b new_branch' into a new directory?

There's a script (new-working-tree or so) in contrib/ that can create a second working tree for a given repo, but I usually prefer to just clone my repo locally. In the second repo, I can then switch branches as much as I like ;-)

Björn

author
#15 lore raw
Quoted 15 lines · Björn Steinbrink

No. Uncommitted changes are, well, uncommitted. They don't belong to any branch yet. A branch is not some structure that contains history in itself. A branch just points to a commit, and the commits, with their parent-child relations, form the actual history. The index and working tree are not part of a branch.

Changing that would even break a workflow that is rather common for me. I start working on something that is either just experimental or assumed to be a very small change. Then I realize that the change is worth keeping and/or too big and deserves its own branch. At that point, I can just do "git checkout -b new_branch", and pretend that I started working on that branch right from the start. With your proposed change, I would need some extra command to transfer the work in progress from the old branch to the new branch.

Quoted 6 lines

If I ever want to switch to another branch and not keep the changes in my working tree and index, I stash them away or create a temporary commit, which I later amend. That's a use-case that comes up rather seldom though (for me at least).

Björn

My proposed change shouldn't necessarily break the described workflow. Git can keep the current behavior for new branches, but automatically 'stash' the changes when checking-out an existing branch. At least having an optional parameter for "auto-stashing" will be nice.

What do you think of that?

#16 lore raw

Dima Kagan wrote (2008-05-11 16:39 +0300):

Quoted 6 lines

My proposed change shouldn't necessarily break the described workflow. Git can keep the current behavior for new branches, but automatically 'stash' the changes when checking-out an existing branch. At least having an optional parameter for "auto-stashing" will be nice.

What do you think of that?

With the fact that Git's branches are just pointers to a commit (and therefore to a history) and that you can checkout anything that refers to a commit (branches, tags, SHA1's, relative pointers like HEAD@{30.minutes.ago}^2~3) I think such auto-stashing would be make things pretty complicated and unintuitive in the big picture. The user interface remains simpler if we just learn to use "git stash" to temporarily put away changes in the index and the working directory when we need to.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#18 lore raw
Quoted 3 lines · Dima Kagan

My proposed change shouldn't necessarily break the described workflow. Git can keep the current behavior for new branches, but automatically 'stash' the changes when checking-out an existing branch. At least having an optional parameter for "auto-stashing" will be nice.

What do you think of that?

you can do just that with an alias, in .git/config add:

[alias]

        auto-stash = !git stash && git checkout $1

then type "git auto-stash master" or "git auto-stash some_branch" and it should stash and checkout the branch.

Cheers,

Pat

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Git for human beings" group. To post to this group, send email to git-users-/[email protected]
To unsubscribe from this group, send email to git-users-unsubscribe-/[email protected] For more options, visit this group at http://groups.google.com/group/git-users?hl=en
-~----------~----~----~----~------~----~------~--~---

#19 lore raw
In reply to Dima Kagan
Quoted 4 lines · Dima Kagan

My proposed change shouldn't necessarily break the described workflow. Git can keep the current behavior for new branches, but automatically 'stash' the changes when checking-out an existing branch.

It's not going to happen, at least by default. Many people already rely on -- and like -- the current behavior, which is often quite convenient (edit some files and then realize "oh, I should commit these to another branch"... no prob! :-).

Occasionally it is inconvenient, of course, but git offers mechanisms to use in such cases, most notably "git stash" (and of course super-cheap local branches which can be amended or even deleted later).

I think the real problem here is that you haven't quite gotten used to git yet.

-Miles

Signature · 2 lines
Faith, n. Belief without evidence in what is told by one who speaks without
knowledge, of things without parallel.
#20 lore raw
In reply to Dima Kagan
Quoted 8 lines · Dima Kagan
Quoted 3 lines

The uncommitted changes survived the branch change and are still in the working tree, in svn just like in git.

Yes, I am aware of that, except one rarely works in one directory on multiple svn branches, because the branches are not private. Git's branches can be private, so perhaps this behavior should be different from SVN?

So if you *want* to use separate working directories for different branches, you can do that in git too. Some people find that more convenient. Other people don't.

Keep in mind, the other difference between git and svn is that until commits are published, they can be freely altered. So many developers who use git tend to commit their changes on the "scratch branches", and then if they need to modify them, use either "git commit --amend" or "git commit --interactive" as necessary to modify the commits on the branches until they are just the way they want them.

I will often have several different features "in progress" at different times, and they are all on scratch branches. By keeping them all on scratch branches, I can test them by creating a new scratch integration branch, and merge the various "in progress" features together to see how they work together, then go back to the individual feature branches to clean them up some more.

When I'm satisified with a particular branch, I'll use "git rebase master" to rebase the work so that it is based off of the head of the development branch, and then do a fast forward merge to merge it into to development branch.

Quoted 1 line

BTW, Is there a way to do 'svn checkout -b new_branch' into a new directory?

Not as a single step operation, no. If you put the following in a script, it will basically do what you want, though.

cp -rl $old_repo $new_repo
cd $new_repo
git checkout $new_branch

It does require that your editor save files by renaming the old file out of the way to file~ and then writing file as a new file, instead of opening the existing file and then doing an O_TRUNC (since that will smash the file on the other repo), but as long as your editor is hard link friendly, this should work just fine, with minimal disk space cost.

Or you can just drop the hard link and just copy the whole repostory using "cp -r" --- after all, svn is horribly wasteful of disk space, with each repository taking twice the amount of space as the working directory, and so if you're used to paying that disk overhead cost with SVN, then presumably you won't mind paying that price with git. There are smarter ways of working, though, if you don't mind altering your work flow a little.

- Ted