post

Gitlab: The source branch does not exist [SOLVED]

Got an interesting error on Gitlab today. On an MR that had passed tests and had been approved, Gitlab would not allow the branch to be merged because “The source branch [Branch Name] does not exist. Please restore it or use a different source branch.”

Checking the “Changes” tab in Gitlab showed all of the changes that I expected to see. So Gitlab could see the changes and knew the branch name.

I checked the commit SHA connected to the branch, and Gitlab showed all of the changes that I expected to see. Gitlab knew the correct SHA and was associating the SHA with the branch name, but the “Overview” tab still showed the error message “The source branch [Branch Name] does not exist. Please restore it or use a different source branch.”

I Googled to see if anyone else had had the issue. Many people had. This issue report on Gitlab.com shows that the problem goes back at least 3 years. The official response from Gitlab is that “This is no longer an active issue.”

I beg to differ. I’m using GitLab Enterprise Edition 14.8.6-ee and it still has this issue.

I cloned a fresh copy of the repo from Gitlab on my laptop and checked the branches with:

git branch -a

The branch was listed. I checked it out. It checked out just fine. I diffed it against the main branch. All of the changes were present.

So the branch exists on the repository on the server, it has all of the changes in it that I expect, there is nothing wrong with the Git repo itself, it’s just Gitlab that has some sort of disconnect.

To work around the problem I added an empty commit to the branch and pushed it to the Gitlab repo:

$ git commit --allow-empty -m "Empty commit"
$ git push

Once I did that the error message cleared. Gitlab had to re-run the tests, but once the tests passed I could merge the branch.

Hope you find this useful.

Update: I spoke to one of the people who manages GitLab Enterprise for my team and apparently Gitlab works by scraping the Git repo for updates and changes using a “scraper service”. If the service is off-line or reset at the time your commit is pushed it’s supposed to pick up any missed pushes when the service restarts, except sometimes it doesn’t work.

As long as the service is on-line the next time you push a commit then Gitlab will pick up the new commit and any missed commits, and everything will be back in sync.

Add an entire directory tree to CVS

A web application project I’m working on uses YUI widgets for the user interface and CVS as the version control repository. We needed to keep separate versions of YUI around for development, testing and production, so we separate the versions by their release numbers.

Adding a new YUI build tree to CVS means adding several hundred new files to CVS. Unlike Subversion or Git, if you add a directory to an existing CVS project CVS doesn’t automatically add all of the subdirectories and files. If you try to add all of the files in a subdirectory using “*” you will also get the CVS directory that CVS uses to store information about the directory’s contents, which will generate warning messages from CVS until the end of time.

If you combine the “find” command with “cvs add” you can add all of the subdirectories and files with one command, skipping all of the CVS subdirectories. The syntax is a little arcane, so I thought it was worth posting here.

For the initial setup assume that I have an existing CVS project “apache” with a directory “js”. I add the directory ~/apache/js/yui to my local copy of the project, copy the YUI zip file into the directory, and unzip it. Unzipping it creates the directory “yui” (in this case ~/apache/js/yui/yui) but since I want separate versions of each copy of YUI I rename the directory and call it “2.8.0r4”. Then I add the new directories to CVS.

# mkdir ~/apache/js/yui
# cp yui_2.8.0r4.zip ~/apache/js/yui/
# cd ~/apache/js/yui
# unzip yui_2.8.0r4.zip
# mv ~/apache/js/yui/yui ~/apache/js/yui/2.8.0r4
# cd ~/apache/js
# cvs add yui
# cvs add yui/2.8.0r4

I want to add the directory ~/apache/js/yui/2.8.0r4/build to CVS as well, but I don’t want to add the “~/apache/js/yui/2.8.0r4/examples” or “~/apache/js/yui/2.8.0r4/docs” directories, just ~/apache/js/yui/2.8.0r4/build, so I use a “find” command that specifies just the “build” directory and I prune out any directories containing the name “CVS” from the results returned by find:

# cd ~/apache/js/yui/2.8.0r4/
# for f in `find ./build -name CVS -prune -o -print | sort`; do cvs add $f; done
# cvs ci -m "Adding YUI v2.8.0r4 to the CVS repository"

Piping find’s results to the “sort” command puts the files in order, so directories always get added before the files that they contain.

To use this technique for your own directories, just go to the parent of the directory you just added and use the above “find” command, just substitute the name of your new directory for “./build”.

A side note: We add a symlink that points to the version we want to use at the moment so that the application code can be run with whichever version we want to test with:

# cd ~/apache/js/yui
# ln -sf 2.8.0r4 current

A script tag in the application would look like this:

<script src="/js/yui/current/build/utilities/utilities.js" type="text/javascript" />

Hope you find this useful.

Renaming a CVS Branch

I recently needed to rename a branch in a CVS repository, and after Googling around for a while I found only hints of what might work, but no actual examples of how to rename a branch. Apparently it’s one thing to rename a tag in CVS, but if it’s a branch tag CVS doesn’t give you any easy ways to rename the branch, and if you try “normal” rename commands on a branch tag you’ll start seeing cryptic error messages. I started fiddling around with some of the commands in a CVS sandbox and figured out how to do it.

If you give a branch the wrong name you can fix the name by adding the good name as a tag name on the same branch, changing your working version to the good name, then deleting the old tag, and finally converting the new tag into a branch tag.

Whoops! I created a bad tag name:

earl@earl:~/sandbox/earl > cvs tag -b bad_name cvs_test.pl
T cvs_test.pl

earl@earl:~/sandbox/earl > cvs up -r bad_name cvs_test.pl
M cvs_test.pl

earl@earl:~/sandbox/earl > cvs ci cvs_test.pl
/cvsroot/sandbox/earl/cvs_test.pl,v  <--  cvs_test.pl
new revision: 1.1.2.1; previous revision: 1.1

earl@earl:~/sandbox/earl > cvs stat cvs_test.pl
===================================================================
File: cvs_test.pl       Status: Up-to-date

   Working revision:    1.1.2.1
   Repository revision: 1.1.2.1 /cvsroot/sandbox/earl/cvs_test.pl,v
   Commit Identifier:   21af497a241a4567
   Sticky Tag:          bad_name (branch: 1.1.2)
   Sticky Date:         (none)
   Sticky Options:      (none)

To fix that, I tag the working revision (in this case 1.1.2.1) of the bad_name branch with the good_name and then switch to the good_name branch:

earl@earl:~/sandbox/earl > cvs admin -N good_name:1.1.2.1
cvs admin: Administrating .
RCS file: /cvsroot/sandbox/earl/cvs_test.pl,v
done

earl@earl:~/sandbox/earl > cvs stat cvs_test.pl
===================================================================
File: cvs_test.pl       Status: Up-to-date

   Working revision:    1.1.2.1
   Repository revision: 1.1.2.1 /cvsroot/sandbox/earl/cvs_test.pl,v
   Commit Identifier:   21af497a241a4567
   Sticky Tag:          bad_name (branch: 1.1.2)
   Sticky Date:         (none)
   Sticky Options:      (none)

earl@earl:~/sandbox/earl > cvs up -r good_name cvs_test.pl
earl@earl:~/sandbox/earl > cvs stat cvs_test.pl
===================================================================
File: cvs_test.pl       Status: Up-to-date

   Working revision:    1.1.2.1
   Repository revision: 1.1.2.1 /cvsroot/sandbox/earl/cvs_test.pl,v
   Commit Identifier:   21af497a241a4567
   Sticky Tag:          good_name (revision: 1.1.2.1)
   Sticky Date:         (none)
   Sticky Options:      (none)

Next I delete the bad_name tag by using the -n option without specifying a revision number:

earl@earl:~/sandbox/earl > cvs admin -n bad_name
cvs admin: Administrating .
RCS file: /cvsroot/sandbox/earl/cvs_test.pl,v
done

earl@earl:~/sandbox/earl > cvs stat cvs_test.pl
===================================================================
File: cvs_test.pl       Status: Up-to-date

   Working revision:    1.1.2.1
   Repository revision: 1.1.2.1 /cvsroot/sandbox/earl/cvs_test.pl,v
   Commit Identifier:   21af497a241a4567
   Sticky Tag:          good_name (revision: 1.1.2.1)
   Sticky Date:         (none)
   Sticky Options:      (none)

earl@earl:~/sandbox/earl > cvs up -r bad_name cvs_test.pl
cvs update: `cvs_test.pl' is no longer in the repository

The bad tag name is gone! To get the good tag again:

earl@earl:~/sandbox/earl > cvs up -r good_name cvs_test.pl
U cvs_test.pl

earl@earl:~/sandbox/earl > cvs stat cvs_test.pl
===================================================================
File: cvs_test.pl       Status: Up-to-date

   Working revision:    1.1.2.1
   Repository revision: 1.1.2.1 /cvsroot/sandbox/earl/cvs_test.pl,v
   Commit Identifier:   21af497a241a4567
   Sticky Tag:          good_name (revision: 1.1.2.1)
   Sticky Date:         (none)
   Sticky Options:      (none)

The last step is to convert the good_name tag into a branch tag:

earl@earl:~/sandbox/earl > cvs tag -d good_name cvs_test.pl
D cvs_test.pl

earl@earl:~/sandbox/earl > cvs tag -b good_name cvs_test.pl
T cvs_test.pl

earl@earl:~/sandbox/earl > cvs up -r good_name cvs_test.pl

earl@earl:~/sandbox/earl > cvs ci cvs_test.pl
/cvsroot/sandbox/earl/cvs_test.pl,v  <--  cvs_test.pl
new revision: 1.1.2.1.2.1; previous revision: 1.1.2.1

There may be an easier way to do this, but this does work.

Hope you found this useful.