0

I'm following this tutorial to import a git history into gerrit.

I have my git history now in a branch 'intermediate'. the git log of master is simply

$ git log
commit b00e1de5676690a8b8c303cd265185578842af9d (HEAD -> master, origin/master, origin/HEAD)
Author: My Name <my.name@mydomain.com>
Date:   Tue Aug 18 18:46:38 2020 +0200

    Initial empty repository

but if I do now

$ git checkout intermediate
$ git rebase master

i get the following:

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: commit message 1
Applying: commit message 2
Applying: commit message 3
Applying: commit message 4
Applying: commit message 5
Applying: commit message 6
Applying: commit message 7
.git/rebase-apply/patch:101: trailing whitespace.

.git/rebase-apply/patch:326: trailing whitespace.

.git/rebase-apply/patch:328: trailing whitespace.

.git/rebase-apply/patch:332: trailing whitespace.

.git/rebase-apply/patch:335: trailing whitespace.

warning: squelched 21 whitespace errors
warning: 26 lines add whitespace errors.
Using index info to reconstruct a base tree...
M       mypath/myfile.txt
Falling back to patching base and 3-way merge...
Auto-merging mypath/myfile.txt
CONFLICT (content): Merge conflict in mypath/myfile.txt
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch' to see the failed patch
Patch failed at 0007 Cleanup refactoring and resolve compilation errors.

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

if I understand git rebase correctly, what it does is start at the commit upon which to rebase and then apply commit by commit on top of this. But if this is an empty commit, shouldn't it be impossible to get mergeconflicts?

matthias_buehlmann
  • 4,641
  • 6
  • 34
  • 76

1 Answers1

1

It's not really clear to me what you mean by empty commit (Git normally refuses to make something that it calls an "empty commit", but what it means is a commit that is no different than its parent: such a commit isn't actually empty, it's just identical in terms of the file snapshot). However, any rebase operation can result in merge conflicts.

if I understand git rebase correctly, what it does is start at the commit upon which to rebase and then apply commit by commit on top of this.

That is, more or less, what rebase does. But consider what happens if you have a repository in which we have these commits:

     C--D
    /    \
A--B      G   <-- branch1
    \    /
     E--F

H   <-- branch2

where commit H has no files at all: it's a snapshot of Git's empty tree. If we now run:

git checkout branch1
git rebase branch2

Git will list out all the commits that it should copy, commit-by-commit, that are reachable from the current branch (branch1) but not from the target commit (branch2 = commit H). So this is commits A, then B, then either of C-then-D or E-then-F, then whichever two of the C-D / E-F pair it skipped earlier. Commit G, being a merge commit, gets dropped entirely.

If commit G had merge conflicts that had to be resolved, these merge conflicts will definitely occur again during the rebase operation. These could be the merge conflicts you are seeing.

Without seeing the commit graph and each commit's snapshot, it is hard to say specifically why you got the conflicts you got, but the theory of operation for Git shows that rebase can indeed have conflicts as a result purely of the source commits, without regard for the --onto target (H in this case).

torek
  • 448,244
  • 59
  • 642
  • 775
  • why are merge commits skipped? – matthias_buehlmann Aug 18 '20 at 18:14
  • That was the original design for `git rebase`: to drop merges and flatten branches. The original implementation used `git format-patch`, which simply cannot represent merges at all and therefore omits them. The modern `git rebase -r` option will keep the topology and re-*perform* each merge, but if the merge had conflicts, you will have to resolve them again, unless you have `git rerere` enabled. – torek Aug 18 '20 at 18:24
  • all I want is to have my existing git history start with that no files containing commit. How can I achieve that without having to resolve all merge conflicts again? – matthias_buehlmann Aug 18 '20 at 18:34
  • It's rarely worth the effort, but if that's all you want, that can be done with `git replace` followed by `git filter-branch`. The reason it's rarely worth the effort: there's a sort of virtual commit of the empty tree before the first commit anyway: `git show` of a root commit will show all files added. Making a new history that starts with a literal empty commit adds no practical value: `git show` of the first commit says nothing useful, and `git show` of the *second* commit now shows every file added. – torek Aug 18 '20 at 19:28
  • 1
    I need it to start with a SPECIFIC empty commit, because this empty commit was generated by Gerrit. I'm migrating an existing git history to gerrit – matthias_buehlmann Aug 19 '20 at 17:57
  • @user1282931: aha, the old externally-imposed constraint thing. In that case I'd suggest the `git replace` trick: look at the `-p` option, which lets you set up a fake re-parent-ing. Once you've set that up, use `git filter-branch -- --all` (with `--tag-name-filter cat` if needed) to build a new commit graph, after which you can delete the replacement made in the first step. – torek Aug 19 '20 at 18:20