Reputation: 700
I have a remote repository on GitHub and a corresponding local repository and workspace.
The issue is like this
If I remove deleted file Bar.java from Staging and commits only Foo.java (only my changes) and do a push to upstream, then the deleted file will appear back in Remote Repo!
If add two files into index, commit it and do a push to upstream then only, the deleted file stays deleted in remote repo I assume this happens when I do a Pull and there is Conflict and as a result my Local Repo didn't updated but my workspace got updated. Is it correct?
Based on that, I have the following questions:
How can I make my Local Repository in Sync with Remote Repo when there is a conflict when I do a Pull?
What happens when I push my local repo to upstream? Will the entire remote repo will be overwritten, or selectively merge my committed changes?
Upvotes: 1
Views: 1273
Reputation: 45819
To fully understand what's happening (or what it means to be in sync with the remote), we need to remember three types of storage area in git: work tree, index, database. You have all three of these locally, and you also care about the database on the remote.
So let's step through a pull
that has conflicts. But to make the picture more clear, let's suppose we do a fetch
first (which is fine, because that's the first step git performs when you ask for a pull
).
So to start, you have a local repo with commits as
I --- A <--(master)(origin/master)
You make some changes locally and commit them.
I --- A <--(origin/master)
\
B <--(master)
But meanwhile your coworker pushed changes to the remote, so it has
I --- A --- C <--(master)
When you fetch
, you get
I --- A --- C <--(origin/master)
\
B <--(master)
At this point, your database has all of the objects from the remote, so you could say that you're fully in sync with the remote. The remote is a bit behind on what you have, though; it doesn't know about B
yet.
Next step of the pull
is to merge origin/master
into master
. If there are conflicts, then the merge stops with the work tree and index in a "merging" state. The index contains changes to files that had no conflict, and your worktree contains conflict markers (along with any non-conflicting changes) for files that had conflicts.
These changes are expressed relative to your local master (i.e. relative to B
) since that's what you're merging into. So "delete Bar.java" is a change being merged into your local branch without conflict - but you can still override it. Even though git only requires you to deal with the conflicts at this point, you can make whatever changes to the commit as you want. Allowing that is good and necessary - because sometimes resolving the conflict requires changes outside the region of the actual conflicting lines; but in this case you probably don't want to do it. So other than add
ing files as you modify them to resolve conflicts, you should probably leave the index alone.
Finally you've resolved conflicts and commit, so you have
I --- A --- C <--(origin/master)
\ \
B --- M<--(master)
Noe that you've created another new commit (a merge) on your master
, and the remote is therefore behind until you push
. You could avoid this commit by pulling with the --rebase
option; the process would be similar, but you'd end up with
I --- A --- C <--(origin/master)
\
B' <--(master)
(where B'
is the rebased replacement for B
). Even so, origin/master
is behind until you push.
With that background understanding, let's specifically address your questions:
How can I make my Local Repository in Sync with Remote Repo when there is a conflict when I do a Pull?
The first step of the pull
is a fetch
which does put you fully in sync in the sense that you have all of the information from the remote. You still have some info that's not yet on the remote (your local commits), and until you've resolved conflicts there's not much you should do about that.
Any perception that you aren't fully in sync is because your worktree and index are reflecting the merge in progress that pull
initiates after the fetch
. (If you had done just a fetch
, you could immediately checkout
to origin/master
and you'd see everything as it is on the remote.)
What happens when I push my local repo to upstream? Will the entire remote repo will be overwritten, or selectively merge my committed changes?
A push
sends updated refs (and other objects as needed to support them) to the remote. So in this case you're pushing the ref for the master
branch:
1) git updates the origin/master
ref in your local repository
2) git makes sure origin/master
is still "reachable" from master
(via parent commit pointers); this means, intuitively, that all changes in origin/master
have been incorporated into master
, so updating the remotes master
as requested will only apply new changes that you've locally added to master
3) if (2) looks good, then:
3a) required objects are sent to the remote and added to its database. In this case that would be commits B
and M
(or commit B'
if you did a rebase
) and objects contained therein.
3b) the remote's master
ref is updated to match your local master
ref
While the master
ref is overwritten, it is not correct to say that the repo is overwritten. You've mostly added data to it. Where this can seem a little fuzzy is, the data you've added can include an instruction to undo a change that had previously been done by someone else. Proper handling of the merge step during the pull is what determines if that happens.
Upvotes: 2
Reputation: 30307
If you decide to keep the file on the revision (discarding the deletion) then it will surely show up on the resulting revision. If you decide to follow suit and keep the deletion on the index then the file will be gone.
Upvotes: 1