1

I ran into a problem where I published a branch to my public git repository that had the wrong parent branch. My attempts to fix this made things worse.

Initially, I had:

  A <-- master
   \
    B <-- abstract-test-rule
     \
      C <-- run-leaf

I pushed abstract-test-rule and run-leaf to my public github repository, and made pull requests for each. I then realized that "run-leaf" included commit B; I had meant to branch "run-leaf" off of "A". So I ran git revert B on branch "run-leaf":

  A <-- master
   \
    B <-- abstract-test-rule
     \
      C--B' <-- run-leaf

I re-pushed "run-leaf" to my public github repository.

Question 1: What should I have done? I'm guessing the correct thing would be to create a new branch off of A with only the delta from commit C, pushed that to my public github repository, canceled the previous pull request and create a new one. What's the easiest way to do that?

Unfortunately, branch "run-leaf" was merged into the parent repository from commit C, and then B' was merged into the parent repo.

I knew the merge of "abstract-test-rule" would now be painful for the owner of the parent repository, so I tried to prepare "abstract-test-rule" for merge. By this time my repo looked like this:

  A <-- master
   \
    B--D--E <-- abstract-test-rule
     \
      C--B' <-- run-leaf

I went into my repo, pulled from the parent repo into "master", and then merged "master" into "abstract-test-rule". The merge was a mess (because, I'm guessing, I was merging the parent repo's version of B' into "abstract-test-rule"). After all this, we have some very confusing diffs.

Question 2: Was there an easier way for me to cleanup "abstract-test-rule"? In other words, I wanted to merge "master" into "abstract-test-rule" but avoid merging my parent repo's version of B' into "abstract-test-rule"

Question 3: What is the best way to verify that the merges to the parent repository were done correctly? Right now, I'm just pulling from the parent repository, merging my version of the branches from "master" (reviewing the diffs from the merge) and running git diff master to verify that the branch is now identical to "master"

Thanks!

NamshubWriter
  • 23,549
  • 2
  • 41
  • 59

1 Answers1

3

Question 1: What should I have done? I'm guessing the correct thing would be to create a new branch off of A with only the delta from commit C, pushed that to my public github repository, canceled the previous pull request and create a new one. What's the easiest way to do that?

It depends on if anyone has already pulled your changes. If no one has pulled your changes you can remove the branch and recreate a new one with the wanted commits. If your changes got into another repo you can only git revert the unwanted commit. As a rule f thumb if you published the branch it is safer to git revert since in most cases you can't be sure that no one pulled the unwanted branch.

edit: changeset transplanting

You can create a new branch with only the C changeset by either

git checkout -b newbranch A # <- branch name or commit-id
git cherry-pick SHA1(C) # repeat for every wanted commit

or

git checkout -b newbranch run-leaf
git rebase -i HEAD~10 # large-enough number to include every commit you want
                      # to strip, and remove every unwanted commit in the editor

Both ways create a new branch with only the wanted commits.

Question 2: Was there an easier way for me to cleanup "abstract-test-rule"? In other words, I wanted to merge "master" into "abstract-test-rule" but avoid merging my parent repo's version of B' into "abstract-test-rule"

As long as the changes are not published, you can git rebase -i the branch history. When the changes are published you can't edit the history.

edit

As your changes are already spread out, so reverting the changeset is the recommended way. You could also have striped out the unwanted changeset with interactive rebase, and git push -f this changes out, but every other who pulled the old branch would likely run into trouble on the next pull of your repo. See this SO question and the git docs for more information about that.

Question 3: What is the best way to verify that the merges to the parent repository were done correctly? Right now, I'm just pulling from the parent repository, merging my version of the branches from "master" (reviewing the diffs from the merge) and running git diff master to verify that the branch is now identical to "master"

You can do the merge on your side so that for the upstream developer these are fast forward merges. That way the upstream developer does no merge on it's own but uses your prepared merge.

Community
  • 1
  • 1
Rudi
  • 19,366
  • 3
  • 55
  • 77
  • To clarify, for Question 2, change B' was published to my repo (in branch run-leaf), and then pulled into the upstream repo (into the master branch). For Question 3, I want to verify that the upstream developer did the merges correctly (there were merge conflicts do to other changes that were pulled in, despite my attempts to keep my branches fresh) – NamshubWriter Jan 13 '11 at 14:28
  • ...and for Question 1, what's the easiest way to to create a new branch with just C (assuming B and C did not touch the same lines of code)? – NamshubWriter Jan 13 '11 at 14:37
  • @NamshubWriter When you have already the wanted merge result locally it is easier to publish the merge. When the other also does the same merge, you only more than double the efforts, since you both do the merge, and you also have to review the others merge result. – Rudi Jan 14 '11 at 08:18
  • So once run-leaf was published, the best fix would have been to pull from the upstream branch, create a temporary branch from master based on the commit that merged run-leaf, revert the upstream's version of B' on that temporary branch, and merge that temporary branch to abstract-test-rule? – NamshubWriter Jan 14 '11 at 14:57
  • @NamshubWriter When you mean the B commit with "the upstream's version of B'", and not the reverse patch ob B, then yes, this is the best solution in this process. Also note that when you reply to some one you need to put @username somewhere in the comment, that will SO cause to send notifications to the person (I got notified because I wrote the answer, but when some one else did it I would got none). – Rudi Jan 14 '11 at 15:26