Git branch and merge

I have been using Git for about a year now, but always in the master branch. I decided to try working in a branch to get experience with merging. Naturally enough, I am now observing some behaviour that I do not understand. I would appreciate any explanation of what is happening and whether this is expected behaviour or not.

I initially pull from the remote repository and then checkout -b workcopy from the master. At this point workcopy and master are identical. In workcopy I modify x.rb and y.rb. I then add/commit x.rb in workcopy. Next I checkout back to master.

From what i had read about git I believed that all the modifications that I made to x and y in workcopy only affectedi workcopy; and that those files in the master branch were still pristine as when they had been pulled. However, when I checkouted the master branch this is what I saw:

$ git co master M y.rb Switched to branch master $ $ git status # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed)

Well you didn't commit y.rb. If you wanna save not commited changes for later use you should use stash.

p.s. I'm sorry if this gets sent twice it wouldn't let me submit because the quote was too long. :slight_smile:

I initially pull from the remote repository and then checkout -b

workcopy from the master. At this point workcopy and master are

identical. In workcopy I modify x.rb and y.rb. I then add/commit x.rb

in workcopy. Next I checkout back to master.

From what i had read about git I believed that all the modifications

that I made to x and y in workcopy only affectedi workcopy; and that

those files in the master branch were still pristine as when they had

been pulled. However, when I checkouted the master branch this is what

I saw:

$ git co master

M y.rb

Switched to branch master

$

$ git status

On branch master

Changed but not updated:

(use “git add …” to update what will be committed)

modified: y.rb

no changes added to commit (use “git add” and/or “git commit -a”)

$

This is because you had not committed the change to y.rb. A checkout will not overwrite modified (uncommitted) files. You should have seen a message when you switched to the master warning that y was modified (M filename). You will think this is the optimum behaviour the when you forget to commit before a switch.

A git diff on y.rb in both branches produced identical output. This

clearly indicates that the changes that I made in the working branch

affected the master branch too. This is something that I thought not

possible. Was I wrong in my belief or am I doing something wrong in my

implementation.

The master has not been affected, it is just the modified file left there.

Further, I noted that x.rb had disappeared from view on the master even

though it had only been commited on the workcopy branch. However, when

I ran merge on the master then I saw this:

I do not understand how x.rb had disappeared from the master, you should see the original x.rb. If x.rb was a new file on the branch then you would expect it to be missing from the master.

Colin

James Byrne wrote:

I have been using Git for about a year now, but always in the master branch. I decided to try working in a branch to get experience with merging. Naturally enough, I am now observing some behaviour that I do not understand. I would appreciate any explanation of what is happening and whether this is expected behaviour or not.

I initially pull from the remote repository and then checkout -b workcopy from the master. At this point workcopy and master are identical. In workcopy I modify x.rb and y.rb. I then add/commit x.rb in workcopy. Next I checkout back to master.

But you didn't commit y.rb so the modifications still exist in your work copy. (not your branch named workcopy, which would be very confusing to me to name a branch that. I'd name it something like experimental or after whatever feature I was working on).

From what i had read about git I believed that all the modifications that I made to x and y in workcopy only affectedi workcopy; and that those files in the master branch were still pristine as when they had been pulled. However, when I checkouted the master branch this is what I saw:

You misinterpreted what you read. The changes you make in a working copy affect the working copy (i.e. the files you see when listing your project files).

$ git co master M y.rb Switched to branch master $ $ git status # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: y.rb no changes added to commit (use "git add" and/or "git commit -a") $

Of course y.rb in your working copy shows the modification because you modified it. You didn't commit it to your branch so git checkout of master merges your working copy changes to what it gets from the master branch effectively patching master's version of the file with your working copy changes. This is expected and good behavior. You wouldn't want git stomping on you local uncommitted changes.

I you have changes in your working copy when working on a branch and do not want to commit those changes permanently, you can "stash" the changes before checking out master. You do this using git stash command. Typically, however, it makes sense to commit all your changes to the branch before switch to another. After all, if it's an experimental branch and you're at a reasonable time to switch away to something else it's okay to just commit everything whether it's fully working or not. It is an "experimental" branch after all.

Please bear with me as I walk through this:

I start with a pull from the remote. I then create and checkout a branch, say localtests. I modify a file X.rb on localtests. If I switch back to the master via git checkout then the change to x.rb comes with me into the master branch? However, if I first commit the change to x.rb on localtests then it does not?

Please bear with me as I walk through this:

I start with a pull from the remote. I then create and checkout a

branch, say localtests. I modify a file X.rb on localtests. If I

switch back to the master via git checkout then the change to x.rb comes

with me into the master branch?

It is not ‘in’ the master branch as it has not been committed, it is just in your working copy, which is the master branch plus your modified file. If you want to get rid of modified files (so your working copy is the same as the current branch or master) you can use:

git checkout . Note the dot on the end. Be careful though, this will destroy any uncommitted changes, do not get into the habit of doing it lightly or you will regret it at some point.

However, if I first commit the change

to x.rb on localtests then it does not?

If you commit it on the branch and switch to the master then the modified file is in the branch but the original is still in the master. You get back to the modified files by checking out the branch again.

I think that I may see where I went wrong. Regardless of which named branch I am on, git automatically puts any changes that I make into what is effectively an anonymous working copy branch, where they remain until they are added to a branch's future commit set. Is this correct?

I think that I may see where I went wrong. Regardless of which named

branch I am on, git automatically puts any changes that I make into what

is effectively an anonymous working copy branch, where they remain until

they are added to a branch’s future commit set. Is this correct?

Not really, they are not on a branch, your working copy is just a set of files in your folders. When you switch branches git overwrites them with the version from the repository for that branch, unless they have been modified but not committed, in which case it does not overwrite them.

The git repository contains all the versions of all the files on all the branches and when you checkout it copies the appropriate versions into your local folders (but not overwriting modified files as we have seen). A commit copies files that you have modified and marked for commit into the repository (on the appropriate branch).

There are a number of good git tutorials on the web, google will find them. Perhaps looking at some of those would help to get the concepts sorted. It all seems a bit complex at first but once you have played with it for a while you will wonder how life managed without it.

Colin Law wrote:

Not really, they are not on a branch, your working copy is just a set of files in your folders. When you switch branches git overwrites them with the version from the repository for that branch, unless they have been modified but not committed, in which case it does not overwrite them.

I'm not sure what version of git you're using, but I just did a sanity check with a simple git repository. The version of git I'm using (1.6.1.3) wouldn't let me switch to another branch with local changes to the working directory. I had to use git checkout --merge master, which then performed a 3-way merge between the versions on the branch, master and working. In this case the file did conflict, as it should have, After using git mergetool to resolve the conflicts then I was able to commit the merged file into the master branch.

Note that in this case both the branch and master had versions of the file committed previously.

Robert Walker wrote:

I'm not sure what version of git you're using, but I just did a sanity check with a simple git repository. The version of git I'm using (1.6.1.3) wouldn't let me switch to another branch with local changes to the working directory.

I am stuck with Git 1.5.5 on CentOS-5.3. Unless and until some kind soul adds a more recent version to EPEL.

Colin Law wrote:

There are a number of good git tutorials on the web, google will find

them. Perhaps looking at some of those would help to get the concepts sorted.

It all seems a bit complex at first but once you have played with it for a

while you will wonder how life managed without it.

As I wrote, I have been using git for about a year now. I converted all

our projects from Subversion last spring. And I have done quite a few

tutorials. I have no trouble in using git, I just now desire to see how

branch and merge works, without following a script so to speak.

When you switch branches git overwrites them with the version

from the repository for that branch, unless they have been

modified but not committed, in which case it does not overwrite

them. The git repository contains all the versions of all the files

on all the branches and when you checkout it copies the appropriate

versions into your local folders (but not overwriting modified files

as we have seen). A commit copies files that you have modified and

marked for commit into the repository (on the appropriate branch).

However, in addition to the forgoing, when I switched from a branch with

modified files into the master branch then git copied the modified files

into the master branch as well.

It is not copying the modified files anywhere, they are staying exactly where they are, the working copy is always in the same place (unless you move the whole tree of folders of course).

This put the master branch into a state

as if I had edited those files in that branch. It was this behaviour

that confused me. I thought that whatever one did in a branch stayed in

that branch and did not follow one around modifying every other branch

that one enters.

Again, the branch is not being modified, a branch is only modified when a commit or similar is performed. It is the working copy that you are talking about.

How does one check for commits, and their contents, made to other

branches but not yet merged back into the master?

I Use gitk

Colin Law wrote:

Not really, they are not on a branch, your working copy is just a set of

files in your folders. When you switch branches git overwrites them

with

the version from the repository for that branch, unless they have been

modified but not committed, in which case it does not overwrite them.

I’m not sure what version of git you’re using, but I just did a sanity

check with a simple git repository. The version of git I’m using

(1.6.1.3) wouldn’t let me switch to another branch with local changes to

the working directory. I had to use git checkout --merge master, which

then performed a 3-way merge between the versions on the branch, master

and working. In this case the file did conflict, as it should have,

After using git mergetool to resolve the conflicts then I was able to

commit the merged file into the master branch.

I am using 1.5.6.3 on ubuntu. I think the situation you are describing may be because the file has been modified on the master and branch. I think if you make a new branch, checkout the branch, modify a file without committing (or staging) then checkout the master it will let you do it and leave the file modified

Colin Law wrote:

I am using 1.5.6.3 on ubuntu. I think the situation you are describing may be because the file has been modified on the master and branch. I think if you make a new branch, checkout the branch, modify a file without committing (or staging) then checkout the master it will let you do it and leave the file modified

This seems to be the case. I built and installed Git-1.6.2-1 and I get the same behaviour as I observed with 1.5.5.

$ git pull ... $ git co -b newbranch $ echo junk > README $ git status # On branch newbranch # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory)

It might help to think of your SVN experience. In SVN when you checkout a branch, you download a *copy* of the files in that branch in the repo. When you commit, you upload your modified files to the branch in the repository.

In Git, although you have your version of repository in a database on your computer, the situation is similar. In Git, when you checkout a branch Git loads the files in that branch from the repo to the working directory, where they show in your file system and you can open them and modify them. When you git commit them, the changes are written to the repo.

In both Git & SVN, you generally make changes to your repository using your vcs commands, and you make changes to the checked-out copy using your editor. In both cases, branches exist *in* the repository, and the files that you are working on have come *from* the repository. The difference is that in Git the repo you are working from is your personal version which is stored on your computer.