Git Balance Changes

I have 3 branches: master, feature, bugfix ... And the commits look like this:

    4-5-6(feature)
    |
1-2-3(master)
    |
    7(bugfix)

      

I did a "git redirect fix function" to test my function with bugfix

    1-2-3(master)
        |
        7(bugfix)-4-5-6(feature)

      

Now I need to rebase creating a pull request for my feature branch without patching, so I did a "git master rebase" function and expected:

1-2-3(master)-4-5-6(feature)
    |
    7(bugfix)

      

Instead, he says the feature has been updated with a wizard. It's true, but I don't want to merge commit 7. I could reload interactively and remove that commit, but I would like to know if there is a better way to do this. I thought that rebase would only carry commits in one branch to another, but it looks like it doesn't.

+3


source to share


2 answers


Something to understand is that rebase does not rewrite history or transfer commits, a commit in Git cannot be changed. Instead, he creates a new story and says that everything was like this. For example, when you start with:

    4-5-6(feature)
    |
1-2-3(master)
    |
    7(bugfix)

      

And then git rebase bugfix feature

what really happens:

    4-5-6
    |
1-2-3(master)
    |
    7(bugfix)-4A-5A-6A(feature)

      

Three new commits are made, 4A, 5A, and 6A. The original commits are still there, but nothing points to them. They will eventually be cleaned out, but they will stay there for a few days.

This means you can undo the rebase, which is what you are trying to do. You need to find where you feature

were before reinstalling. This can be done with a help git reflog

that tracks every time it moves HEAD

. This happens to be checkout

, commit

, reset

and rebase

. git reflog

maybe something like:

65e93ca (HEAD -> feature) HEAD@{0}: rebase finished: returning to refs/heads/feature
65e93ca (HEAD -> feature) HEAD@{1}: rebase: 3 feature
6d539a3 HEAD@{2}: rebase: 2 feature
3cd634f HEAD@{3}: rebase: 1 feature
b84924b (bugfix) HEAD@{4}: rebase: checkout bugfix
a9fd2f1 HEAD@{5}: commit: 3 feature
29136bc HEAD@{6}: commit: 2 feature
60543b0 HEAD@{7}: commit: 1 feature
c487530 (master) HEAD@{8}: checkout: moving from master to feature

      

This tells me that a9fd2f1 was the last function commit before it was reinstalled. Instead of re-doing the rebase, I can just move the function back.

git checkout feature
git reset --hard a9fd2f1

      



In the future, this kind of thing becomes much easier if you git tag

initial position the function before doing the rebase. Then you can git reset

go back to that tag without searching in the reflog.


As for your specific problem, the problem is that after reinstalling, your repository now looks like this:

6A [feature]
|
5A
|
4A
|
7 [bugfix]
|
3 [master]
|
2
|
1

      

When you ask git rebase master feature

Git, notes that the master is already the ancestor of the function and does nothing. It doesn't matter what bugfix is ​​in between.

Instead, you need to tell Git that you only want to reinstall 4A, 5A, and 6A and ignore 7. This is done using syntax --onto

.

git rebase --onto master bugfix feature

      

This indicates the need to reinstall, but does not include fixes for the function on master.

I would recommend using git reset

rebase instead of trying to redo. There is no guarantee that the second rebase will be the same, especially if there were conflicts. If with using git reset

you explicitly revert to the old state of the repository.

+2


source


I thought rebase would only push commits in one branch to another, but it looks like it doesn't.

This is the key: your commit 7

on your diagram is on a branch feature

. It's also in the branch bugfix

. Commits 1-2-3

are found in all three branches.

Sections

Git is very different from most other version control systems. The branch "contains" the commit only because of the "reach" ability that makes the commit pointed to by the branch name. Branch names such as master

, bugfix

and feature

, simply point to one particular commit that Git calls the tip of the branch. He himself does, forming a chain, through each fixation "back" to his predecessor.

It git rebase

actually copies commits because of this : you went from:

        4--5--6   <-- feature
       /
1--2--3      <-- master
       \
        7      <-- bugfix

      

in

        4--5--6   [abandoned - used to be feature]
       /
1--2--3      <-- master
       \
        7      <-- bugfix
         \
          D--E--F   <-- feature

      

where D

is a copy of the original 4

, E

is a copy 5

, and F

is a copy 6

(I used the 4th, 5th and 6th letters here so we can copy 7 onto G

if we want, but this technique is about to end.)

You can still get what you want. You just need to copy over again D-E-F

, or - it's probably better for this particular case - go back to the abandoned, original 4-5-6

.

When you use git rebase

to copy fixes, the originals are glued. There are two names by which you can find them: ORIG_HEAD

and reflog names. The name is ORIG_HEAD

overwritten by various other commands, but you can check if it all points to a commit 6

:



git log ORIG_HEAD

      

and you will probably recognize your originals.

Reflog names are of the form name@{number}

, for example feature@{1}

. The chunk number

grows every time you change the commit that the chunk points to name

, since Git just stores the current value name

in the reflog and the rest is slice.

Hence:

git log feature@{1}

      

should show you the same as it git log ORIG_HEAD

, except that it feature@{1}

works longer (maybe becomes feature@{2}

, feature@{3}

etc. over time). By default, the previous values ​​for each name are retained for at least 30 days, so it will take enough time to return.

To get it back, use git reflog feature

to find out which number goes in the part @{...}

, and then, while on feature

( git checkout feature

), run:

git reset --hard feature@{1}

      

or whatever the number (although checking again with help git log

first is a good idea).

(This assumes you have nothing to log anything, i.e., which git status

says everything is clean because it git reset --hard

destroys unchecked indexes and work tree changes.)

+2


source







All Articles