Switching `main` branch hi all, we are using OSS ...
# help
h
Switching
main
branch hi all, we are using OSS version of lakefs. We have the situation where we mistakenly merge a wrong branch to main. We started with this: A good branch, then branch out and had a bunch of bad commit on a "bad-branch" And then merged bad-branch to main ! With git, we would just delete main, and create a new main out of the good branch. But I cannot delete main branch, nor changing the default branch of the repo to something else ... One solution is just delete data in main and then re-copy all files from the good branch. But is there a more efficient way ?
i
Reverting all commits is I think the best but the api to do this is not fluently when I encountered it
a
I think you could hard-reset
main
to whatever you like. It's an API-only call; exposing it on lakectl would be very unsafe. (One day we will have a reflog and it will be safer; until that day, you'll need to use the API.)
h
so basically using python sdk to move the main HEAD to previous commit ??
a
Also any of these might be a useful feature request: • Allow changing default branch • Allow deleting the default branch • Allow making a different branch default
so basically using python sdk to move the main HEAD to previous commit ??
Yup, it's the best I have right now.
šŸ‘ 1
h
a
i
would be cool if we can do reset --soft origin/main and then push --force-with-lease
and then server side checks are done whether its safe to do
a
Yeah, the problem is not so much soft vs. hard resets, it's that any such command loses the previous branch HEAD. Now in Git if this happens, you
git reflog
and discover from where it came. But such an operation on CLI with no way to undo is incredibly dangerous in a data product.
i
isnt it possible to maintain a reflog server side?
pardon my ignorance šŸ˜› I dont know the exact internals in lakefs
a
isnt it possible to maintain a reflog server side?
I believe this is the way to do it. But it's a fair amount of product work, followed by a fair amount of dev work. One day we'll get there.
🤟 1
h
Hard reset is not doing anything for me ... Here is a code showing it. The output:
Copy code
Creatd branch hardreset-20251127170412
Current HEAD of 'hardreset-20251127170412': f7b8dee66468e7d1c9b82cf4e4b2a3599d75bdb0106bc1bf1147e79e53b3331e
Upload successful - changes will be committed atomically
Transaction committed to main
Current HEAD of 'hardreset-20251127170412': a84e61da290707df70f8f11f306c5108274fd5c1ff7fe4bdec1eb2857ea231de
Hardreseting to f7b8dee66468e7d1c9b82cf4e4b2a3599d75bdb0106bc1bf1147e79e53b3331e for branch hardreset-20251127170412
Current HEAD of 'hardreset-20251127170412': a84e61da290707df70f8f11f306c5108274fd5c1ff7fe4bdec1eb2857ea231de
Prior commit ID: a84e61da290707df70f8f11f306c5108274fd5c1ff7fe4bdec1eb2857ea231de
Post-reset commit ID: a84e61da290707df70f8f11f306c5108274fd5c1ff7fe4bdec1eb2857ea231de
Expected commit ID: f7b8dee66468e7d1c9b82cf4e4b2a3599d75bdb0106bc1bf1147e79e53b3331e
Hard reset failed.
Can anyone reproduce this ? Using OSS 1.72 both on server and sdk
a
Hi @HT, I'm sorry, I am unable to reproduce this issue. Things I tried: • Hard reset the branch - worked. • Hard reset the branch from the Python (low-level) SDK - worked. • Look over the hard-reset code from controller.go downwards, looking for a way it might return 2xx without down anything - could not find such a path. Note that I did not use your code. Very strange...
h
šŸ¤”
There is nothing in the logs. But I think our is currently not very verbose. I might ask our Cloud Engineer to bump the loglevel in the hope that something show up ...
Anything else I could try ?
a
Are you perhaps somehow using two different lakeFS clients, one for the high level SDK connected to one server, and another for the low-level SDK connected to another server? TBH I don't see something like that in any of the code you sent, but I'm not a great Pythonista.
h
You said that from the go code, we cannot increate the verbosity of the current hard reset call ? Because in the python SDK, I only get a None as result of that API call ...
a
Sorry, that is clearly wrong: the OpenAPI spec says it returns nothing. You're right, I just ran getCommit on the branch.
In any case I no longer suspect a client SDK language issue.
h
wait, so you can reproduce the issue you mean ?
a
No no, sorry. No reproduction over here.
Hang on... can you print the type of each of your branch objects in the high-level SDK? Perhaps one of them is a Reference?
h
type of each of your branch objects
There is suck function in the high level API ? when I do
Copy code
print(lakefs.repository(repo_name,client=clt).branch(branch_name))
I get:
Copy code
Branch(repository="test-repo", id="init")
is that what you are after ?
a
OK, if you create a new branch object each time then it has the right type - it's a Branch. Was worried you might be calling Reference.get_commit instead of Branch.get_commit - references don't move, branches do. But you don't, so my worries were unfounded. And I still don't know what's different in your setup. Suggest you look at logs if at all possible. Even run your code on a local repo on a local installation. Sorry.
h
Just spin up a local lakefs with docker compose:
Copy code
# This docker-compose file provides an ephemeral lakeFS quickstart instance for local development.

services:
  lakefs:
    image: treeverse/lakefs:latest
    ports:
      - 8000:8000
    environment:
      LAKEFS_INSTALLATION_USER_NAME: "quickstart"
      LAKEFS_INSTALLATION_ACCESS_KEY_ID: "AKIAIOSFOLQUICKSTART"
      LAKEFS_INSTALLATION_SECRET_ACCESS_KEY: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
      LAKEFS_DATABASE_TYPE: "local"
      LAKEFS_AUTH_ENCRYPT_SECRET_KEY: "THIS_MUST_BE_CHANGED_IN_PRODUCTION"
      LAKEFS_BLOCKSTORE_TYPE: "local"
Got lakefs server version 1.73 And same issue: hard reset did not move the branch head ...
Log with DEBUG level
I don't see the API call for hard reset on the server side !
I think the SDK is broken : I can call with whatever parameter (wrong repo, non existing branch, ...) and it never raise exception !
a
Wow, I hope you're wrong šŸ˜• . The good news is that "on my machine" I can get a 404 from calling it with a nonexistent repo. Which SDK version are you running? (Not sure how to check in Python what is actually running)
lakefs_sdk.__version__
I guess.
h
Copy code
lakefs==0.9.1
lakefs-client==1.44.0
lakefs-sdk==1.72.0
lakefs-spec==0.11.3
and now upgraded to
Copy code
lakefs==0.14.0
lakefs-client==1.44.0
lakefs-sdk==1.73.0
lakefs-spec==0.11.3
Do you need some flag somewhere to enable Experimental API ?
a
Nope.
Anything experimental or internal is "just" not subject to the versioning guarantees. So we could change it in a way which is not backwards compatible. But we only do that if we discover that we designed it really badly. Eventually we either graduate experiments or remove them. This one hasn't seen much use to go either way. And I know we did not change it (no server-side diffs). let me test it on my machine; as I don't use much Python I tend to run ancient versions of the SDK.
OK, I just tried 1.73.0 with bad args. It works perfectly:
Copy code
>>> import lakefs_sdk
>>> lakefs_sdk.__version__
'1.73.0'
>>> import lakefs
>>> c = lakefs.Client()
>>> 
>>> 
>>> c.sdk_client.experimental_api.hard_reset_branch('no-such-repo', 'reset-me', ref='123456789')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 40, in wrapper_function
    return vd.call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 134, in call
    return self.execute(m)
           ^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 206, in execute
    return self.raw_function(**d, **var_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api/experimental_api.py", line 1953, in hard_reset_branch
    return self.hard_reset_branch_with_http_info(repository, branch, ref, force, **kwargs)  # noqa: E501
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 40, in wrapper_function
    return vd.call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 134, in call
    return self.execute(m)
           ^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/pydantic/v1/decorator.py", line 206, in execute
    return self.raw_function(**d, **var_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api/experimental_api.py", line 2064, in hard_reset_branch_with_http_info
    return self.api_client.call_api(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api_client.py", line 410, in call_api
    return self.__call_api(resource_path, method,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api_client.py", line 222, in __call_api
    raise e
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api_client.py", line 212, in __call_api
    response_data = self.request(
                    ^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/api_client.py", line 462, in request
    return self.rest_client.put_request(url,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/rest.py", line 288, in put_request
    return self.request("PUT", url,
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/pypypy/lib/python3.12/site-packages/lakefs_sdk/rest.py", line 232, in request
    raise NotFoundException(http_resp=r)
lakefs_sdk.exceptions.NotFoundException: (404)
Reason: Not Found
HTTP response headers: HTTPHeaderDict({'Date': 'Thu, 27 Nov 2025 10:37:16 GMT', 'Content-Type': 'application/json', 'Content-Length': '35', 'Connection': 'keep-alive', 'X-Content-Type-Options': 'nosniff', 'X-Request-Id': 'ce4f2065-b118-4503-9e32-cc0857554c0b'})
HTTP response body: {"message":"repository not found"}
Do I correctly understand that when you do this you do not get a 404??
h
you don;t need to auth with the lakefs server ??
let me try your flow
a
Use the high-level SDK:
Copy code
c = lakefs.Client()
It reads .lakectl.yaml and environment variables and usually just does the right thing.
h
Ok. Now I get the 404 with your api style
let me dig from here
a
Thanks! So (for now...) I don't need to worry we released a broken SDK, right? 😌
h
Horray !!!!!!
got it reset !!!
This is bad:
Copy code
with lakefs_sdk.ApiClient(configuration) as api_client:
    # Create an instance of the API class
    api_instance = lakefs_sdk.ExperimentalApi(api_client)
    repository = "FOO" # str |
    branch = "Whatever" # str |
    # ref = initcommit
    ref= "whever"
    force = True # bool |  (optional) (default to False)

    try:
        # hard reset branch
        api_instance.hard_reset_branch(repository, branch, ref, force=force)
    except Exception as e:
        print("Exception when calling ExperimentalApi->hard_reset_branch: %s\n" % e)
which I got from your doc page
So the solution is: please rectify the docs ??
Thank you for your patience !!
a
This is strange. We will look into it. In the meanwhile, I'm glad you're back on track!