Меню Закрыть

Would be overwritten by merge aborting

Содержание

I have an extremely simple repo for a single module. I have a "develop" branch into which I want to merge a "feature" branch. My develop branch is clean with nothing to commit. I committed in my feature branch, the checked out the develop branch. When I tried git merge —no-ff featurebranch Git aborted with error "Your local changes to the following files would be overwritten by merge". I’m not sure what to do now . the only file I changed in featurebranch was a file named styles.css . I do want my changes merged into the develop branch version of styles.css

3 Answers 3

That you are getting this error implies that something isn’t "clean".

My develop branch is clean with nothing to commit.

But this doesn’t make sense, in Git, because branches are never clean or dirty, no matter how we define the word "branch". (See What exactly do we mean by "branch"?) What’s clean, or not-so-clean, in Git are the index and/or your work-tree.

Before we define these two terms—you’ll need some pretty good definitions to proceed with the merge—we should first make note of the fact that Git is really all about commits. Branches, or more precisely branch names like develop and feature , are mostly just sops to us mere humans, who can’t deal with the actual names of commits, which are big ugly hash IDs.

Each commit has its own unique hash ID. Each commit stores data—a full snapshot of all of your files—and some metadata: the name of the person who made the commit (e.g., your name), email address, date-and-time-stamp, and so on. One of the really important pieces of metadata is the hash ID of the parent of the commit as well, or—in the case of merge commits—the hash IDs of all of its parents. Git links commits together, in a backwards fashion, using these parent hash IDs. The linked discussion above talks about how this backwards-connected chain of commits is also what we mean by the word "branch", at least sometimes.

Once a commit is made, nothing about it can ever be changed, by anyone or any thing. If the commit is no good, you can make a new and improved one and stop using the bad one, but you can’t actually change the bad one. So a commit is a commit: it’s not clean, it’s not dirty, it’s just a commit. It either exists, and it is; or it doesn’t, and isn’t.

On the other hand, the index can be "clean" or "dirty", and so can your work-tree. The terms "clean" and "dirty" are not well-defined and not very formal, though the gitglossary does actually define them (only in terms of the work-tree though). Before we jump into the next bit, we should define exactly what the index and work-tree are, though.

The work-tree is where you do your work

Files in a commit are frozen forever. They literally can’t be changed. So they’re great for archival—you can see every snapshot of your files from every previous commit—but they’re quite useless for getting any actual new work done.

To get new work done, Git must first extract a commit into a work area. Your work-tree is this work area. It has all your files, in their regular old format, that your computer can use. The files in the commits are in a special, read-only, frozen, compressed, Git-only format. Basically, nothing can use them until you rehydrate them, and when you do, they go into your work-tree.

Your work-tree is "clean" if it matches . well, something. The gitglossary doesn’t say exactly what, though it uses the phrase "not committed". It’s "dirty" otherwise.

Note that your work-tree can contain files that you have never committed to Git at all, and never plan to commit. Git calls these files untracked. These files aren’t in the repository! They’re just lingering there in your work-tree, which is, after all, an ordinary directory (or folder if you prefer that term) on your computer, so it can contain as many or as few files as you like: you’re in control, not Git. If you don’t put these files into Git, they’ll stay untracked.

Читайте также:  Почему тупит ноутбук виндовс 10

The index is more complicated, but we can call it the proposed next commit

Besides the frozen, read-only, Git-only copy of your files in whichever commit you checked out, and the useful copy of your files in your work-tree, there’s a third copy 1 of all of your files. Well, that is, there’s a third copy of all of your tracked files. For the most part, this is what the index is.

The index, also called the staging area or (rarely now) the cache, holds this third copy of each file that will be in the next commit you make. These files are already in the special Git-only format, ready to be committed. In fact, the presence of a file in the index / staging-area is what makes the file tracked. An untracked file is in the work-tree but not in the index. A tracked file is in both. 2

The existence of this third copy is why you have to git add files all the time. When you git add a file, Git freezes the content into a new file, or discovers that it’s already there in some existing file from some earlier commit or whatever, and puts that frozen copy in the index, ready to go into the next commit. Until then, what’s in the index, ready to go into the next commit, is the copy of the file from the commit you checked out.

If you don’t change the index copy of a file, the next commit re-uses the current commit’s copy. If you do change it, the next commit has the updated file. Either way, what’s in the index can be described, at all times, as the proposed next commit.

During a merge, the index takes on an expanded role, but we won’t go into the details much here. We’ll talk about it a bit in the next section below.

The gitglossary doesn’t talk about a "clean" or "dirty" index, but we can define it similarly. If the index / staging-area exactly matches the current commit, it must be "clean": there are no files in it that, if we replaced them from some other commit, we might lose them. If not—if the index has in it some files that aren’t in the current commit, or whose contents has changed—then the index must be "dirty". We can clean it out in two ways:

  • write it to a new commit (e.g., git commit or git stash —note that git stash makes commits!), or
  • remove any new files entirely, and replace any existing files with the copies from the current commit (e.g., git reset HEAD ).

Obviously, the latter risks losing files. For instance, if we do:

then our precious data is only in one copy of new-file that exists in the index / staging area. If we didn’t remove the work-tree copy, removing the index copy would be safe—or at least safe-ish—because we’d still have the work-tree copy. But if the "precious" content is really just trash after all, that’s fine.

1 Technically, the index holds a reference to an internal Git blob object, rather than a whole separate copy. The blob object is shared with any other commits that already have that version of that file. If it’s not shared, it’s just a blob object ready to go into a future commit. Once it’s committed, it will be shared—it’s already in the frozen, read-only, Git-only format. If you replace the index copy, Git makes a new frozen-format blob object, or re-uses an existing frozen-format blob object, automatically.

2 If the file is in the index, but missing from the work-tree, it’s still going to be in the next commit. If you want the next commit to omit the file, you must remove the index copy. Now the proposed next commit says that the next snapshot won’t have the file either.

Note that when Git checks out a commit that doesn’t have the file, Git will remove the work-tree copy, and when Git checks out a commit that does have the file, Git will re-create the work-tree copy from the committed version. This gets complicated if you want to keep the file around as an untracked file!

Читайте также:  Как отретушировать фото на компьютере

With all this ironed out, now we can get to merging

What git merge does is to find, then combine, three versions of each file:

  • One copy comes from whatever you have in the current commit ( HEAD ). This commit has a snapshot, i.e., a whole bunch of files.
  • One copy comes from the argument you gave to git merge : featurebranch . This branch name identifies one specific commit, namely the tip commit of that branch. This commit also has a snapshot.
  • The third, and in some ways most crucial, version of each file comes from the merge base. The merge base is a commit, and Git finds this commit on its own. Git does so using the parent information in each commit.

We’ll skip the details of how Git finds the merge base, but you can run:

to see which commit(s) is / are the merge base(s) of HEAD and featurebranch .

When I tried git merge —no-ff featurebranch Git aborted with error "Your local changes to the following files would be overwritten by merge".

This means that the work-tree copy of each listed file doesn’t match something—the index and/or the committed copy.

For Git to do the merge, it will read all three copies into an expanded version of the index. Instead of the index holding just one copy of each file, each file in the index acquires three numbered slots, and Git fills those in from each of the three commits in question:

  • Slot 1 gets the file from the merge base.
  • Slot 2 gets the copy of the file from HEAD .
  • Slot 3 gets the copy of the file from featurebranch .

If all three copies match, or if two of the three match, Git’s job is easy: it can shrink the three copies down to just one, leave that in the index (at the normal "slot zero"), and put that one into the work-tree as the merge result. Basically, the rules here are:

  • Nobody changed the file: all three match, any will do, we’re good.
  • You changed the file and they didn’t: two match, yours is the right one, move slot 2 to slot 0 (and put it in the work-tree) and clear out the other slots and we’re done.
  • They changed the file and you didn’t: two match, theirs is the right one, move slot 3 to slot 0 (and put it in the work-tree), clear out the other slots, and we’re done.

It’s also possible that you and they both changed the file, but both to the same new file. In this case slots 2 and 3 match and Git can use either of those and clear out the other slots as above.

There are some more, stickier, cases where the file doesn’t exist in some of the three commits, but if it does exist in all three, the last remaining case is that you both changed the file, in different ways. Git will now attempt to combine your changes and their changes. If this combining fails, Git leaves all three slots in place, puts its best-effort at combining the files into the work-tree—overwriting whatever was there—and leaves you to clean up the mess.

Git doesn’t work out the final result, then go back and check if it’s OK to start

Notice that in the course of merging one set of three files above, Git may need to scribble over the copy of the file in the work-tree.

Git could try to do the merge without touching the work-tree at all. If it did that, and if the merge worked all the way through and no work-tree files needed to be replaced, Git could do a merge with a dirty work-tree. But it doesn’t even check: instead, it just checks to see if the work-tree is dirty.

Git will need to scribble all over the index. So it needs a clean index.

Your git merge refuses to start because the index and/or the work-tree are dirty. The exact error message implies that the problem is the work-tree.

Читайте также:  Что такое бэк фронт фокус

To fix it, make sure the work-tree is truly clean. There are a few special cases that are annoying:

You might have a file that’s untracked in your commit. This file is just there in your work-tree. It’s neither "clean" nor "dirty", it’s just a file.

If they have that file in their commit, though, your merge will need to copy that file from their commit into your work-tree. That will overwrite the file.

The solution to this is to save the file in a commit (i.e., forever-ish) or just move it out of the way, to a different untracked file, or completely out of the work-tree. Run the merge, then figure out what to do with your version of the file.

You can use git stash to save it temporarily, but this just makes some commits that are not on any branch, leaving you with the problem that you’ll have to merge those commits back in to get the stuff out of them, which will cause the problem again. I don’t recommend using git stash at all.

Or, you may have used git update-index with the —assume-unchanged or —skip-worktree flags. These let you have a file in your work-tree that’s also in your index, then let you change the work-tree copy without having Git nag you to update the index copy too. New commits you make will use the index copy, which no doubt came out of some earlier commit.

The merge process cannot leave this file alone! It has to work with the committed copies. The solution to this problem is similar: move the file out of the way. Re-extract the index / commit copy and turn off the flag(s) with git update-index —no-assume-unchanged and/or git update-index —no-skip-worktree . Now that everything is back to being treated normally, and the file is clean, git merge can work.

After you merge, you can turn the index flag(s) back on and put your copy back, if that’s what you want.

This is all pretty painful and I recommend not making heavy use of —assume-unchanged and/or —skip-worktree . (I’ve done it myself, for various reasons, but I don’t recommend doing it. 🙂 )

Сборник заметок для разработчиков.

Сборник заметок для разработчиков.

Рубрики

Архивы

Доработка / модернизация / исправление сайтов на OpenCart

При использовании git, наверное каждый встречался с ошибкой команды git pull при скачивании изменений удаленного репозитория,

strong > error : Your local changes to the following files would be overwritten by merge : / strong > protected / data / shop . dbprotected / runtime / application . logPlease commit your changes or stash them before you merge . AbortingUpdating f2b24b5 . . a9e818e

Для решения этой проблемы достаточно выполнить всего 2 команды в консоли/

& gt ; strong > git fetch — all / strong >
Fetching origin

Эта команда скачает нам все ветки но не смержит их в локальном репозитории.

Далее используем команду :

& gt ; strong > git reset — hard origin / master / strong > HEAD is now at a9e818e Last Commit

Этой командой мы сбросим все изменения с ветки origin/master

Вот и все! Далее делаем git pull

& gt ; strong > git pull / strong >
Already up — to — date .

Готово! Теперь мы скачали все изменения из ветки master в ваш локальный репозиторий!

I am new to git and left to work with live server.

After few successful git pull actions, on the latest one I got this error:

I tried git stash , but nothing happen — the error on git pull is still there.

How can I perform git pull and not mess anything on the server?

1 Answer 1

You need to do git add before the git stash

Use git worktree

git worktree allow you to work on different branches at the same time, Here you can see that one folder is "dirty" while the second one isn’t

They both using the same (single) repository

If you use rebase later on:

  • Note: (Since Git 2.7)
    you can also use the git rebase [—no]-autostash as well.

Рекомендуем к прочтению

Добавить комментарий

Ваш адрес email не будет опубликован.