问题
I have a Git repository with two branches: master
and Release/v1.0
. On master
there's a branch policy that I cannot directly push to it, I can just contribute through Pull Requests.
Now, I'm fixing a bug on Release/v1.0 and want to merge it to master. Therefore I do the following:
// create a new branch from master where I merge the changes from Release/v1.0
git checkout -b merge-to-master
// start the merge
git merge origin/Release/v1.0
// merge gets committed automatically, so I just need to push (to upstream if the branch doesn't exist remotely)
git push
Now I'm making a Pull Request from merge-to-master
to master
. Once the PR is completed, I have all changes in master
.
The merge works as expected. However, When I start the merge once more, I would expect that those commits do not show up again, because they have already been merged. But the commits are showing up again and again in the merge view.
I assume that the merge info is not written correctly? Now my question: Am I doing something wrong? How do I avoid the same commits to show up over and over?
@UPDATE:
also, when I want to delete a local branch (git branch -d v1.0/212760-wrong-status
- which is a feature branch), it tells me:
error: The branch 'v1.0/212760-wrong-status' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v1.0/212760-wrong-status'.
But, I already made a PR to Release/v1.0 (and completed it), so I would consider it as fully merged. But why is Git having a different opinion? :)
回答1:
I think, but cannot be sure from the information provided, that this is the key:
I can [only] contribute through Pull Requests
When you deliver a pull request to someone else, you are asking them to take some action. We need to know who the them is. Who are they? Let's find out what, precisely, they are doing!
Let's start with this:
v1.0/212760-wrong-status
I think this means you have done:
git checkout -b v1.0/212760-wrong-status v1.0
or equivalent in your own repository, and then made a commit or two here to fix a bug. You then do the:
git checkout -b merge-to-master master
git merge origin/Release/v1.0
git push
steps. (It will help a great deal if you draw out the actual steps and actual commit hash IDs and branch names involved here, so that everything is concrete with actual hash IDs.) Note that git push
will push the actual commits to some other repository, such as the one you call origin
or the (presumably different / separate) one you call upstream
; each push will ask that other Git to set some branch name(s) to point to specific commits.
At this point, let's also give everyone names so that we know who is taking which action. I will call you Dave and talk about Dave's commits, which have the specific hash IDs you can see in your repository or repositories (run git log --all --decorate --oneline --graph
to see the abbreviated hash IDs and the graph). I don't have a name for the person operating the upstream repository; let's call her Ursula, which starts with U for Upstream.
Furthermore, these days, "pull request" usually implies a hosting service like GitHub or Bitbucket. GitHub in particular offers a clicky button, "merge pull request", with a pulldown menu attached to it. Clicking on the pulldown menu rather than the "merge pull request" button offers three options, which change the action of the clicky button:
Merge. This is a straight merge: Ursula will add to Ursula's (upstream) repository, one or more commit made by Dave from Dave's web-hosted repository copy. Dave's commit(s) will have the hash IDs of Dave's commits, because they are Dave's commits. Ursula will create one new commit with one new, unique hash ID.
Rebase and merge. This makes copies of Dave's commits. Ursula will add these copies to Ursula's repository, after which Dave's commits are essentially dead—Dave should replace them with Ursula's copies.
Squash and merge. This makes one single new commit, belonging exclusively to Ursula, that makes the same changes as Dave's N commits (however large N is, even if it's just 1). If N = 1 this is remarkably similar to "rebase and merge", though the default commit log message is different. In either case, Ursula's new single commit obviates all of Dave's original commits, just as with the rebase-and-merge mode.
Once Ursula has finished, you (Dave) can git fetch
her commit(s)—there's always at least one of hers—from the address you spell using the word upstream
. If hers is a true merge, she will have merged the commit you made (I believe) on v1.0/212760-wrong-status
. That is, that exact commit, with its same hash ID, is now present in Ursula's repository. Her merge into her master
has a different hash ID from your merge into your master, but it does use your original commit.
If you then, in your own repository on your computer (not your origin
on GitHub or whatever), check out your master
and fast-forward it to her merge commit (now showing, with git log --all --decorate --oneline --graph
, on your upstream/master
) and then run:
git branch -d v1.0/212760-wrong-status
your Git will see that the commit that is the tip of your v1.0/212760-wrong-status
is merged to your current branch master
. That is, by looking at Ursula's merge commit's second parent, your Git can trace a direct line from your master
to that particular commit. So that commit is contained in master
, and Git will be happy to delete the name v1.0/212760-wrong-status
from your local repository.
Since this isn't the case, we can conclude that Ursula must have used the "rebase and merge" or "squash and merge" mode of the clicky button to make a copy of your commit. If the copy is good enough—if you are happy with the way Ursula copied your commit—you can safely forcibly delete your branch name, losing your original commit (eventually forever though your reflogs will probably retain it for another 30 days or so, if you change your mind).
In other words, if Ursula has copied your commit to a new and supposedly improved commit that obviates your original commit, is is now up to you—Dave—to decide whether Dave's original commit should be discarded in favor of this new copy. That's what your Git is telling you.
If you don't discard your own commit like this, your next pull request could—depending on how you build it up—re-introduce this commit. Whether it will depends, as usual, on the actual commit graph. The commit graph—the one that git log --graph
draws—is what matters. You provide actual commits, which come with actual graph segments, through your pull requests. If they take your actual commits, your graph segments get added, and now you and they share graphs. But if they don't take your commits, they'll add some other commits with different graph segments. Your Git will add their commits to your graph, giving you an ever-bigger graph with lots of copies of commits. It's up to you do decide how you wish to deal with that.
来源:https://stackoverflow.com/questions/49649073/git-is-merging-commits-over-and-over