1

I've a git issue that I've not read anywhere so please explain this to me. Let's say both me and a co-worker starts working from commit A. At this point file X wasn't exist. Both me and my co-worker have created the file without knowing. He pushed a few, so we were standing at commit E. I've tried to git pull, but OFC it told me that my local files would be overwritten, I should stash then. OK, I've used git stash, tried to pull again. Git said there are local conflicts showing that file called X and that therefore it can't pull. Ok, I've git stash poped back, made a commit. Then I've pulled and the git automerge told me that it is going to merge the conflicts. OK, at the end the file X had the content what I've pushed, and my co-workers work was gone permanently.

So what happened? I've somehow overwritten the file on the server or what? How is that even possible?

Bert
  • 347
  • 7
  • 25
  • 2
    Did you resolve the merge conflict before that final commit after the stash pop? If not, that might be the problem - you may have created a commit which effectively undid everything your co-worker did because that would have been resolved during the conflict resolution. Check your commit logs and see if that's what happened. – Mark Embling May 18 '17 at 11:59
  • 1
    [Duplicate](http://stackoverflow.com/questions/9823692/resolving-a-both-added-merge-conflict-in-git)? – Quentin May 18 '17 at 12:00
  • Piece back together the correct file by checking out your partner's version. – Tim Biegeleisen May 18 '17 at 12:02
  • 1
    Don't Panic(tm). Whatever happened, I'm sure your co-worker's changes are not gone permanently. They are still in the remote repo, to say the least. – jingx May 18 '17 at 15:59
  • No panic here. Already got the file back, but the even still conserns me. Why didn't the `git stash` command stashed the files so I could pull the new files? – Bert May 18 '17 at 16:27

2 Answers2

2

MVCE would help

It would help if you showed, step by step, exactly what you did, or—even better—provided a minimal, complete, verifiable example (also known as an MVCE). Of course, the point of your question is that you don't know quite how you did this in the first place. But the thing is, we don't either! We can only guess.

My guess is that you never git added the file in the first place. Let's look at my MVCE. I start by making a one-commit repository with a master branch, with just a README file. (These commit messages are terrible, by the way.)

$ mkdir tt; cd tt
$ git init
Initialized empty Git repository in ...
$ echo demo failure to save file in stash > README
$ git add README
$ git commit -m initial
[master (root-commit) 0442487] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README

Now let's make your co-worker's branch, which you would eventually bring into your repository as origin/master. We can't make a remote-tracking branch this way (I could do it by cheating) so let's just use a regular branch:

$ git checkout -b other
Switched to a new branch 'other'
$ echo new file X > X
$ git add X
$ git commit -m 'new file X on branch other'
[other 37681f5] new file X on branch other
 1 file changed, 1 insertion(+)
 create mode 100644 X
$ git checkout master
Switched to branch 'master'

Now we are ready to go back to you being yourself. Let's make a new file and fail to git add it. Let's also modify README: we'll need this to make git stash do anything. We can git add the README change, or not git add it, whichever we prefer; this part will make no difference.

$ echo our new file X is different from his > X
$ echo 'add extra line to readme' >> README

You now ran git pull and got a complaint. We literally can't run git pull here, but we don't have to: all git pull does is run git fetch to get commits from your upstream remote, and then run git merge to merge those commits into your current branch. I always recommend that those new to Git avoid git pull: it's full of traps for the unwary, and you will have more problems than if you just use the two separate commands yourself.

So, we'll do the two-separate-commands thing. But: we do not (we can not) git fetch your wo-worker's commit in this example, which is why we made a branch named other above in the first place. So we just go right to the second command, git merge:

$ git merge other
Updating 0442487..37681f5
error: The following untracked working tree files would be overwritten by merge:
    X
Please move or remove them before you merge.
Aborting

(Note, by the way, that when you run git pull, it effectively runs git merge origin/master, rather than git merge other. We are using other here because we made this, rather than getting it through git fetch.)

What stash does, and doesn't do

We have now reached the stage at which you ran git stash. Had you run git status first, you would have seen this, which might have been a clue, though it's hard to know at first what parts of this deserve what amounts of attention:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    X

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

The two interesting bits of information here are that we have a modified, but not yet staged, README, and—this is more important for our git stash step—the untracked file X.

Anyway, let's run git stash (which means git stash save) now:

$ git stash
Saved working directory and index state WIP on master: 0442487 initial
HEAD is now at 0442487 initial

Let's take a look at git status now (I am guessing you did not—this is a mistake; you should check git status frequently):

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    X

nothing added to commit but untracked files present (use "git add" to track)

There's that pesky X still! The point here is that git stash save doesn't save untracked files by default. (You can get it to do so, but if you had, that would have been even worse. Don't do this until you truly understand merging and merge issues: you'll get yourself into a huge trap that can only be resolved by understanding merge issues. This is yet another reason to avoid git pull: if you learn to use git merge directly, you will be on your way to understanding merges and the occasional problem.)

Now let's simulate git pull again. Once again we must skip the fetch step and go straight to git merge:

$ git merge other
Updating 0442487..37681f5
error: The following untracked working tree files would be overwritten by merge:
    X
Please move or remove them before you merge.
Aborting

And here we have it: git stash failed to help.

Let's try undoing the existing stash (which will put README back into the modified-but-not-added mode) and then git add X. Normally I recommend using git stash apply first, checking the result carefully, and then using git stash drop only if you are happy with that result, but we'll just run git stash pop, which means git stash apply && git stash drop:

$ git stash pop
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    X

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (1e7d19ea701fcc3dd8e0157c9a8a8555f74316a4)

Enough about git stash! Let's go on to normal commits and merging...

Now we'll git add the two files and commit, rather than stashing:

$ git add README X
$ git commit -m 'created file X'
[master 699e149] created file X
 2 files changed, 2 insertions(+)
 create mode 100644 X

Now we can merge. (Or, we could fetch-and-merge, via pull, if we had a remote. But there's nothing new to fetch, and we don't have a remote. And besides, it's time to learn how merges work! So let's just merge.) We will get an add/add conflict:

$ git merge other
Auto-merging X
CONFLICT (add/add): Merge conflict in X
Automatic merge failed; fix conflicts and then commit the result.

Again, in your own case, you would be doing git merge origin/master—or just plain git merge, which uses your current branch's upstream setting, which is presumably origin/master. But one way or another, we now have this "add/add conflict".

Resolving conflicts

When Git stops a merge with a conflict, it means Git doesn't know what to do. You must help it out here. You can run git status to see how far Git got:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both added:      X

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

Git has left, in our work-tree, the file X. But there are two files named X: ours, and your co-workers (which we're simulating as other). Which one did Git leave us? Here's what is in X:

$ cat X
<<<<<<< HEAD
our new file X is different from his
||||||| merged common ancestors
=======
new file X
>>>>>>> other

So, the answer is that it left both versions of X in the work-tree. (I have merge.conflictStyle set to diff3 so mine shows "merged common ancestors" here. If you have the default merge.conflictStyle setting, Git won't show that part. Since there are no common ancestors, that part is empty anyway—it's not really useful here. It's only useful when there are common ancestors, during a modify/modify conflict.)

It's now your job to come up with a merged version of X, or perhaps separate out the two versions into two different files. Precisely what you want, and how you want to do it, is up to you. Let's say we'd like to rename our X to something else, and extract their (your co-worker's) X intact:

$ git show HEAD:X > X.ours
$ git checkout --theirs X
$ cat X.ours
our new file X is different from his
$ cat X
new file X

Now git status will show the new untracked file X.ours, as well as the conflicted file. Let's git add both the adjusted X (back to his version only) and the new X.ours:

$ git add X.ours X
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   X
    new file:   X.ours

Since we're now ready to commit, we can conclude the merge now with git commit.

(This is an example of correctly resolving the add/add conflict. I note that you say that this is not what happened; but I don't know what you did do, and without more information, I can't even guess what that was. I've been concentrating, above, on what git stash can't do: it cannot help with add/add conflicts, and it does not save untracked files by default.)

torek
  • 448,244
  • 59
  • 642
  • 775
0

First thing, When you have used git stash save, After the command it should have no modified files available, and then if you have git pulled your branch, then the conflicts should not be available / happen. Hence I am saying your firstever git stash save did not worked successfully.

Second, if after you have git pulled your branch successfully, the work of your co-worker has auto-merged with your branch, which should be available.

Kindly check your git log via :

git log --name-status

then, Check your code difference via :

git show <<Commit ID>>

whether your requierd code is available, or not.

LuFFy
  • 8,799
  • 10
  • 41
  • 59
  • "... I am saying your firstever git stash save did not worked successfully." Yes, I'm aware of it and I'm asking what could have made this. Even tho I was using `git stash`, not git `git stash save` Log: commit A - from me (created file X) from A - commit B - by co-worker from B - commit C - by co-worker (created fileX) from C - commit D - by co-worker from D - commit E - by co-worker from A - commit F - by me Auto merge by me from AutoMerge - commit G - by me .....etc So it looks normal, somewhy stash wasn't working. But why couldn't it? – Bert May 18 '17 at 13:02