Satyajit Roy
Satyajit Roy

Reputation: 547

Files in a branch is automatically adding to main branch

I am learning git. I have created a new branch named 'development' and in that branch when I am creating a file it is automatically adding to the main branch even I did not staged that file.

In the main branch there was two files named one.txt and two.txt.

I just checkout to development branch by

git checkout development

Then I created a file named three.txt by echo three > three.txt in the development branch. I did nothing after creating the three.txt file. I even didn't staged the file.

After crating the file I checkout to the main branch and I saw three.txt there. But how it is possible?

I don't want to have the file in main branch before I merge it.

This is happening like sync system. If I staged a file form any branch it is automatically staged in the main branch and vice-versa. What is the solution? How can I solve this problem? Help me please.

OS: Windows 10

git version: 2.32.0

I used both power-shell and git-bash and getting same result.

Upvotes: 2

Views: 3231

Answers (3)

torek
torek

Reputation: 489888

You've made a simple but fundamental mistake: you think your file is in a branch, or in branches. It's not. Your new file is not even in a commit.

To understand what's going on here, first, remember that Git is not about files. It's not even about branches, really. What Git is all about is commits. Until you make commits, things aren't in Git at all.

Commits do contain files, and branches—or more precisely, branch names—help Git (and you) find commits. So branch names matter, and Git will save files, by containing commits that themselves are found via branch names. But it's the commits that matter. Everything is all about the commits.

I even didn't stage the file ...

As a result, the file is what Git calls an untracked file.

It's important to understand what each commit is and does for you. A commit—as found by its big ugly hash ID, e.g., 670b81a890388c60b7032a4f5b879f2ece8c4558—holds a snapshot of every file that Git knew about, at the time you (or whoever) ran git commit to create that commit. It also holds some metadata, or information about the commit: who made it, and when, and so on. The metadata included in any one commit includes the raw hash ID—which Git uses to find a commit—of the commit's parent.

The parent hash IDs allow Git to work backwards. Given some way to find the latest commit's hash ID, Git can extract that commit. This commit stores all your files, plus the metadata; the metadata gives the hash ID of the previous commit, which also stores all your files and has metadata of yet an earlier commit. We can draw that like this, using uppercase letters to stand in for the hash IDs:

... <-F <-G <-H

We just need to give Git the hash ID of the last commit in this chain, H, for Git to be able to find the remaining commits. We typically do this by giving git checkout or git switch a branch name: that tells Git to extract the last commit that's on that branch. (This also becomes the current commit, in the process.)

These snapshots, each of which holds every file, combined with the backwards chain, is the history in the repository. History is simply the series of commits that Git finds by working backwards.

Now, to avoid using up tremendous amounts of disk space, Git stores these files in a special, read-only, compressed, Git-only, and de-duplicated form. None of the rest of the programs on your computer can work with these files: only Git can read them, and literally nothing can write them. (No part of any commit can ever be changed after the commit is made.)

This means that in order for you to use a commit, Git must extract the commit. It has to take the snapshot-archive of all files, in the special Git-only form, and extract the files, just like extracting any archive works. The result is a set of files that you can see and work on/with. These are the files in your working tree.

When Git fills your working tree with files taken out of a commit, Git puts a "copy" of each file into what Git calls, variously, the index or the staging area, or sometimes (rarely these days—mostly in flags like git rm --cached or git diff --cached) the cache. I put the word "copy" in quotes here because Git uses the pre-compressed, pre-de-duplicated form, and since these files are—by definition—in a commit, they're not actually files at all, they're just references to the already-saved committed copies.

So: checking out a commit populates your working tree and Git's index. You now have files that you can see and work on/with, and Git has prepared the next commit to use exactly the same files.

When you use git add on a file, Git will:

  • check to see if that file is already in the index / staging area: if so, Git kicks that copy out of the index / staging area;
  • pre-compress and de-duplicate a copy of the working tree version of the file; and
  • insert that "copy" (which is already de-duplicated in case it appears in any existing commit) into the index / staging-area.

Unless the file is actually committed, this file is also not really "in" Git yet.1 If it was in some previous commit, of course that file is still in that previous commit, and Git will share it in your next commit. Otherwise, Git will put it into your next commit as a new real (compressed) copy of the file. But that doesn't happen until you run git commit.

Once you do run git commit, Git makes a new commit using all the files that are in its index / staging-area at that time. Then the file is in Git. But until then, the file is merely in your working tree, either unstaged, or staged. The word staged here, as seen in git status, just means that the copy in Git's index / staging-area is different from the copy (or lack of a copy) in the current commit.

Now that the file is committed, it's safe for Git to remove the (now-tracked) file when you switch from this commit, where the file exists, to some other commit, where the file doesn't. Until you commit the file, though, it's not safe to remove it, and Git normally won't.

If the file is untracked (is not in Git's index / staging-area at all), it's just an untracked file sitting in your working tree, and Git won't touch it one way or another. So switching from one commit to another, as you might do by switching from one branch name to another, won't affect the file either.


1There are technical details here, in that if things go badly wrong, you can sometimes retrieve a so-called "dangling blob" to get the file's data back. But you normally don't need to pay any attention to this.

Upvotes: 2

cn0047
cn0047

Reputation: 17091

If you run git status you'll see this file in next section:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)

Also you can see hint here what to do next with you file, (you can stash your file as well).

Technically your file doesn't belong to any branch yet, b/o you didn't commited it yet, so git will keep track of this file with purpose don't lose your changes even when you change branch.

Upvotes: 3

mwryl
mwryl

Reputation: 672

Your third file three.txt is not part of the main branch nor the development branch. It is just an untracked file in both branches. If you type the command git status it will appear as an untracked file.

You need to specifically add it to the development branch and commit it to make it part of it.

Upvotes: 1

Related Questions